MAME 2000, 2003, 2003-Plus, 2009, 2010, 2014, 2015, 2016 and UME 2015
search the folder of the loaded game for their sets and never the system
folder: osd_get_path gives FILETYPE_ROM the content path (mame2003 and
mame2003-plus src/fileio.c:217-220), -rompath is MgamePath (mame2009
retromain.c:432-434, mame2014 retromain.c:1851-1856, mame2015 and
ume2015 retromain.c:1980-2042, mame2016 retromain.cpp:1364-1402), ROMs
open with libretro_content_directory (mame2010 romload.c:667-685) or
IMAMEBASEPATH (mame2000 libretro.c:1044-1053, 1247). Their 421 sets are
load_from: content_dir. Samples, artwork, cheats and the data files read
from the system folder keep their paths.
A set read beside the game goes to the roms folder of each system the
platform launches the core for: libretro_systems, the default core of a
rom folder, the cores a system offers under its own name, the systems a
RetroPie package registers (the lr-mess packages build SUBTARGET=mess,
lr-mess2016.sh:31, and read none of these arcade sets). A roms root in
the install tree takes a plain dest, as a standalone entry placed there.
A platform with no folder per system, or none it can place (RetroArch,
Lakka, RetroBat, EmuDeck, MyMinUI), names the set as read outside the
BIOS folder. EmulatorJS writes the BIOS and the game to one folder
(emulator.js:845, 990, 1054): RomM keeps its firmware entries. Game data
read beside the content is left to the game.
Manifests: roms folders gain 408 files on RetroDECK, 182 on RetroPie,
179 on Recalbox, 140 on AmberELEC, 134 on KNULLI, 52 on Batocera and
ROCKNIX, 39 on EmuELEC. BIOS root copies no other core reads leave: 80
on RetroArch, Lakka and ROCKNIX, 61 on EmuELEC, 60 on Recalbox, 59 on
AmberELEC, 57 on RetroPie, 26 on MyMinUI, 20 on RetroDECK, 19 on
Batocera and EmuDeck, 16 on KNULLI, 13 on RetroBat. verify --all keeps
its severity and status counts.
A platform that binds part of a standalone layout leaves the entries no
binding covers in a folder outside the BIOS tree: they are no longer
packed at the BIOS root, and the manifest names them (root: emulator,
outside_bios_folder). A launcher that executes a profile's file binds
the program folder: in the BIOS tree, below the roms directory a registry
entry names (root: roms, installed into the folder holding the BIOS
folder), or nowhere a pack reaches. A moved entry resolves by its own
path as well as by its destination.
uae4all gains kick.rom and rom.key in its working directory and loses a
not_bundled_on that named Recalbox, which runs uae4all-rpi. lexaloffle
declares that its programs read beside their executable, lists the
Windows build RetroBat runs and the pico8_dyn ROCKNIX runs on x86_64.
A core that loads the first of several names (yabause: saturn_bios.bin,
sega_101.bin, mpr-17933.bin) needs one of them. Profiles wrote this as
required on the first name and optional on the others, so verify and
the gap report called saturn_bios.bin a missing required file while
sega_101.bin was held, and a set held only through a name marked
optional read as a need met by an optional file.
Model: an explicit group on the file entry, mirroring the platform
field. priority was not reused: it is a rank, read by slot.py, region.py
and truth.py inside a (system, region) slot, and that slot is not the
set. px68k-sdl ranks its IPL list and its font list each from 1 in one
system, pom2 ranks one list per machine model, DuckStation ranks 105
images across every region and takes any of them. A rank cannot say
where one list ends. priority stays the order inside a group.
Readers, through alternatives.settle_sets:
- verify --emulator and the emulator pack: a held member fills the
set, the others leave the report, a set nobody holds is one gap
under its first member naming the others.
- find_undeclared_files (verify platform, core complement of packs and
manifests): same rule, a platform declaration or launcher counts as
answering the set.
- cross_reference: excused members are set aside as other versions.
- slot.py: ranks compare members of one set only.
- archive members: a required set inside an archive is met by one.
- truth: a member gives no requirement of its own, one_of and
one_of_required carry the set, and the exporters and the diff leave
such a line's required as the platform wrote it.
- validate_schemas: members of a group share required.
diff_truth read sha1, md5 and crc32 and let one shared value settle the
entry, while export_native corrected each of the four fields on its own.
contradicted_hashes is now the single decision both read.
A platform declaration that names only an md5 left the size check
undecided, and an undecided same-named match overrode a profile's
system:. The size the database holds for that md5 now refutes it: clk's
Oric basic10.rom no longer joins Batocera's BK list.
The first core to tag a file set its region. The pack's region index takes
the union of the tags and voids it on an untagged reader: the truth now
applies the same rule (psxonpsp660.bin, epr-17952a.ic8).
LRPS2 reads pcsx2/resources/GameIndex.yaml through its data directory
and declares no file entry for it, so the truth entry other cores build
named armsx2 and yaps2 alone and hash_conflict missed LRPS2's copy. A
core whose data directory holds a file at an entry's path now folds in
as a reader with the cached copy's hashes, unless the profile lists what
it reads under that tree (yaps2, pcee2).
When two cores declare different values for one file, the truth keeps the first and marks the entry hash_conflict. Its hashes pair an entry and never replace the platform's: armsx2's GameIndex.yaml no longer overwrites System.dat's line for LRPS2.
Systems a core covers without a file were added while walking a set,
so the hash seed placed them and two runs wrote dist/truth/<platform>.yml
in two orders. The normalized system map was built from a set too.
Ymir reads sega_101.bin or saturn_bios.bin, so the sega_101.bin entry
carries saturn_bios.bin as an alias. kronos, yabause and yabasanshiro
open saturn_bios.bin and fall back to sega_101.bin: they were in that
entry's _cores but not its _required_by, while their saturn_bios.bin
entry had them requiring it. A reader that requires one of an entry's
aliases now requires the entry. No reader is added, and same-name
entries kept apart by path are left alone. No export changes.
Recalbox hashes a .zip by its members. diff_truth set that composite
against the profile's container md5 and reported neocdz.zip and
neocd.zip as mismatches. _hash_mismatch now drops it through
comparable(), the rule pair_entries and the export already apply.
_enrich_hashes repeated "ground truth" five times with capitalised
insistence for a three-step lookup, and the MAME ZIP rebuild listed
three guarantees of which two were the same.
--emulator accepts a buildbot core name from a profile's cores:, and a
mistyped target gets the closest names instead of every target. diff_truth
shows destinations and reports unpaired entries as evidence, not removals.
The verify summary counts discrepancies, a shared destination names both
systems, a truth hash conflict names both cores, and pipeline steps carry
their place in the real run instead of N/8. Every GitHub API caller takes
the token from github_token(), which falls back to gh auth token.
The pack leaves out what an emulator installs itself
(validation.deliverable); the truth did not. RetroPie's gngeopi help
asked users to copy gngeo_data.zip, which make install puts in the
package's data directory, and amiberry's whdboot tree, scummvm's extra
data and dosbox-x's FREECG98.BMP went into platform lists as files to
bring.
The truth applies deliverable per platform and per build: an entry
nobody has to bring is kept and marked bundled, never added, still
corrected where the platform declares it. A rebuilt archive is
installed only when every member is. The runner written beside an
addition is the build that needs the file (_brought_by), and the
RetroPie sentence names only what its package's core must be given.
DuckStation identifies its BIOS by MD5 in a folder it scans
(bios.cpp:208), so its entries' names are labels. The export wrote them
into Batocera's and ROCKNIX's lists as files to hold: a user with only
scph5501.bin read 104 missing BIOS where DuckStation boots. Labels also
lent their md5 to a name another core opens, and paired by name they
replaced System.dat's scph5000.bin hashes.
found_by: name | content, on a profile or a file and keyed by build like
load_from. The truth records which cores open each name (_named_by). A
label pairs with a platform entry by hash only, is never added, merges
with an opened name only on a shared hash, and is counted in the export
report rather than listed as missing.
A name the platform declares filed an entry under that system before
its own system:, and the last declaration of a name won. fmsx's 16 KB
DISK.ROM went to nec-pc-88 for quasi88's 2 KB disk.rom and came out as
a second DISK.ROM line under "NEC - PC-8801"; dosbox's SC-55
ROM1.BIN/ROM2.BIN went to galaksija.
A declaration now files an entry only when it can be the same file: a
shared hash, or no size both admit. The same content declared under two
systems is filed under both, an entry's own system stands against a
refuted homonym, and a systemless profile's placeholder takes only names
the platform does not declare. Merging reads the same size rule, so a
24 KB ROM and an entry capped at 16 KB stay two files.
validation: names what the code verifies. dosbox checks
MT32_CONTROL.ROM against nine sha1 and size; the truth's one md5 and
crc32 describe one of those revisions, and the export wrote them beside
System.dat's own sha1, a rom line no file satisfies, and replaced
Batocera's md5. pcsx_rearmed and DuckStation check scph1001.bin by size,
and the v2.0 md5 platforms name was replaced by v4.1's.
checked_hashes keeps a hash the code does not name only where a checked
hash pins one content. Otherwise it still pairs a renamed file but never
corrects or fills a value the platform wrote. Additions keep every hash.
diff_truth reads the same rule.
A profile states where the code reads a file as path: or destination:,
and the resolver reads both. The truth copied path only: redream's
dc_bios.bin, read at dc/boot.bin, reached the export with no path, so
System.dat's dc/boot.bin was not seen and a dc_bios.bin line was added,
and Batocera got bios/dc_bios.bin instead of bios/dc/boot.bin.
Each truth entry claimed its platform line in turn, so the first one to
arrive won. dosbox-x's system.rom (alias bios.rom, no path) took
Batocera's np2kai/BIOS.ROM by name before np2kai's own np2kai/bios.rom
was tried, and the export wrote an IBM PCjr md5 on it. A path also
outranked a contradicting hash: the truth's MSX.rom joins bluemsx's path
and fmsx's md5, which replaced the blueMSX dump on Recalbox's and
System.dat's Machines/Shared Roms/MSX.rom while fmsx's own line held it.
pair_entries runs each test over every entry before the next, tests that
contradict no hash first. export_native and diff_truth both read it.
Dropping the double-dash asides left 72 comments and docstrings with
half a dash glued to the next word ("shape -a size or a size range -is
all"). They now read as a colon, a comma or parentheses, and a prose
style test names any that comes back.
Generating the model for every platform met the same two GameIndex.yaml declarations once per platform, and check_freshness opened on six identical warnings.
diff_truth matched by name with a rank, export_native by path, guarded name and hash: on current data each named files the other did not. Both now read one matcher, which also accepts aliases and sha256.
Batocera, RetroBat, Recalbox and ROCKNIX offer some emulators both as a
libretro core and standalone. Filed as standalone only, the libretro
layout was dropped: libretro Dolphin had no dolphin-emu/Sys/GC files.
Platforms now name dual-mode emulators and each gets both layouts.
The truth model merged a pathless entry into another core's entry of
the same name even when their contents disagreed, so the export wrote
one core's size next to the other core's md5.
The markdown report wrote to a directory named after the tooling that
happened to produce it. It takes --report-dir now, defaulting to
reports/, so nothing in the tree names anything but the project.
Em-dashes replaced throughout the sources and tests, rephrased rather
than swapped for a comma where the dash carried an apposition.
_diff_system reached complexity 42, and its hash-based rename fallback
is the part that stands alone: a platform is free to call a file
whatever it likes, so a name matching nothing is not yet a gap, and
counting one file as both missing and extra invents a discrepancy.
That step is now its own function at complexity 31, with the tests it
never had: pairing on any of the three digests, case folding, non-string
values, and the case where two files simply have no hashes and so are
not evidence of anything. diff_truth output is unchanged.
Run ruff check --fix: remove unused imports (F401), fix f-strings
without placeholders (F541), remove unused variables (F841), fix
duplicate dict key (F601).
Run isort --profile black: normalize import ordering across all files.
Run ruff format: apply consistent formatting (black-compatible) to
all 58 Python files.
3 intentional E402 remain (imports after require_yaml() must execute
after yaml is available).