diff --git a/emulators/00_example.yml b/emulators/00_example.yml index b7e3a7100..6f43c3a15 100644 --- a/emulators/00_example.yml +++ b/emulators/00_example.yml @@ -4,7 +4,11 @@ core_classification: pure_libretro source: "https://github.com/libretro/libretro-core-info" profiled_date: "2026-03-22" source_commit: "bd81a0b73b50449c0862b65bd755d87860925f65" -core_version: ~ +core_version: "v1.22.2-3-gbd81a0b" +version_basis: + kind: tag + tag: "v1.22.2" + distance: 3 display_name: "Example Core (.info template)" cores: - 00_example diff --git a/emulators/2048.yml b/emulators/2048.yml index 149ba2d96..b979db5af 100644 --- a/emulators/2048.yml +++ b/emulators/2048.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/libretro-2048" upstream: "https://github.com/gabrielecirulli/2048" profiled_date: "2026-03-22" source_commit: "39333f7b13dc4daea7c151d9c38d22b961246343" -core_version: "1.0" +core_version: "v1.0" +version_basis: + kind: file + path: "libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "2048" cores: ["2048"] systems: [] diff --git a/emulators/2600-emu.yml b/emulators/2600-emu.yml index 21eb79ad0..4a889f7a3 100644 --- a/emulators/2600-emu.yml +++ b/emulators/2600-emu.yml @@ -7,6 +7,10 @@ profiled_date: "2026-08-11" source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" upstream_commit: "289a40f1b63022b8bbe5b722061c660009d5de2c" core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/metadata/conf.mk" + pattern: '^metadata_version\s*=\s*(\S+)' display_name: "Atari - 2600 (2600.emu)" mode: standalone cores: diff --git a/emulators/2ship.yml b/emulators/2ship.yml index 8b8c6e53a..dfe5b4dac 100644 --- a/emulators/2ship.yml +++ b/emulators/2ship.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/2ship2harkinian/2ship2harkinian" source_commit: "8a24047fbce8915993804e7819f4df4fa591551f" profiled_date: "2026-10-20" core_version: "5.0.1" +version_basis: + kind: tag + tag: "5.0.1" + distance: 0 display_name: "The Legend of Zelda: Majora's Mask (2 Ship 2 Harkinian)" cores: [2ship] systems: [2ship] diff --git a/emulators/3dengine.yml b/emulators/3dengine.yml index 14f091617..c311bacf4 100644 --- a/emulators/3dengine.yml +++ b/emulators/3dengine.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/libretro/libretro-3dengine" profiled_date: "2026-03-22" source_commit: "efa2bf6f32f930721fe9ae2361d7ec858077c483" core_version: "v1" +version_basis: + kind: file + path: "libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Test Core - 3D Engine" cores: [3dengine] systems: [] diff --git a/emulators/3dsen.yml b/emulators/3dsen.yml index 01eb8faa0..50d413574 100644 --- a/emulators/3dsen.yml +++ b/emulators/3dsen.yml @@ -8,6 +8,9 @@ version_source: pattern: '[Vv](?:ersion\s*)?(\d+(?:\.\d+)+)' profiled_date: "2026-08-07" core_version: "1.1" +version_basis: + kind: unverified + why: no_artifact display_name: "3dSen (3D NES)" cores: - 3dsen diff --git a/emulators/81.yml b/emulators/81.yml index 7860258da..f69854522 100644 --- a/emulators/81.yml +++ b/emulators/81.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-22" source_commit: "fa7094910d040baa5fd8b11dbf6a1a618330ecd9" upstream_commit: "4de3cdb8cff0060ad03e43ae2681b0628a9c5f5d" core_version: "1.0a" +version_basis: + kind: file + path: "src/libretro.cpp" + pattern: '#define\s+VERSION\s+"([^"]+)' display_name: "Sinclair - ZX 81 (EightyOne)" cores: ["81"] systems: diff --git a/emulators/a5200.yml b/emulators/a5200.yml index 2a8f26dca..5d3744763 100644 --- a/emulators/a5200.yml +++ b/emulators/a5200.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/alekmaul/a5200" profiled_date: "2026-03-22" source_commit: "40c6f2f1ad4a3145b328d5baaf010fae6c7e752b" core_version: "2.0.2" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: 'info->library_version\s*=\s*"([^"\s]+)' display_name: "Atari - 5200 (a5200)" cores: - a5200 diff --git a/emulators/a7800.yml b/emulators/a7800.yml index c6a9cc7c5..efbcab113 100644 --- a/emulators/a7800.yml +++ b/emulators/a7800.yml @@ -7,6 +7,10 @@ profiled_date: "2026-08-08" source_commit: "7a2afdc1ea08fc331b16b750d8c1f02d4ef62fc8" upstream_commit: "39eb9e44c394df9aec8186f2d2ef7517ace232e1" core_version: "5.2" +version_basis: + kind: file + path: "makefile" + pattern: '#define BARE_BUILD_VERSION \\?"([^"\\]+)' display_name: "Atari - 7800 (A7800)" cores: - a7800 diff --git a/emulators/abuse.yml b/emulators/abuse.yml index b0d2c799d..e2def0df1 100644 --- a/emulators/abuse.yml +++ b/emulators/abuse.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/Xenoveritas/abuse" profiled_date: "2026-10-04" source_commit: "c855a923cd7fb27b629b4e1af78b1fcc5f263d01" core_version: "v0.9.1" +version_basis: + kind: tag + tag: "v0.9.1" + distance: 0 display_name: "Abuse" cores: [abuse] systems: [] diff --git a/emulators/ace-dl.yml b/emulators/ace-dl.yml index a3efc25a7..53fa25297 100644 --- a/emulators/ace-dl.yml +++ b/emulators/ace-dl.yml @@ -8,6 +8,10 @@ version_source: pattern: 'New release <i>[^<]*</i> - (\d{4}/\d{2}/\d{2})' profiled_date: "2026-10-20" core_version: "2026/10/16" +version_basis: + kind: package + url: "https://roudoudou.com/ACE-DL/" + artifact: "BNDGEN.tar.gz (ACE-DL Linux x86-64 build), release date on the download page" display_name: "Amstrad - CPC/Plus (ACE-DL)" cores: - ace-dl diff --git a/emulators/advanced_drastic.yml b/emulators/advanced_drastic.yml index 541d8251c..620b41e0a 100644 --- a/emulators/advanced_drastic.yml +++ b/emulators/advanced_drastic.yml @@ -8,6 +8,10 @@ profiled_date: "2026-10-22" source_commit: "eaf41ab9bc8adcc15c010bf9517bc94c38e7bffd" pin_frozen: "KNULLI, the only platform that ships it, builds this revision (KNULLI package/emulators/advanced_drastic/advanced_drastic.mk:7 at tag 20260511). Later commits are not part of that build." core_version: "r2.5.2.0" +version_basis: + kind: file + path: "drastic" + pattern: "Version (r[0-9][0-9.]+[0-9])" display_name: "Nintendo - DS (advanced_drastic)" cores: - "advanced_drastic" diff --git a/emulators/advanced_tests.yml b/emulators/advanced_tests.yml index 4540fa076..0bed39a68 100644 --- a/emulators/advanced_tests.yml +++ b/emulators/advanced_tests.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/libretro/libretro-samples" profiled_date: "2026-03-22" source_commit: "7c2ad112d7a5176de2191e473369668da8946b16" core_version: "v1" +version_basis: + kind: file + path: "audio/audio_callback/libretro-test.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Test Core - Advanced Test" cores: - advanced_tests diff --git a/emulators/advancemame.yml b/emulators/advancemame.yml index 7a8398eac..5ece6fafe 100644 --- a/emulators/advancemame.yml +++ b/emulators/advancemame.yml @@ -5,7 +5,12 @@ source: "https://github.com/amadvance/advancemame" upstream: "https://www.mamedev.org" profiled_date: "2026-10-26" source_commit: "81670476672b59f430518a63e9a116db58ed6232" -core_version: "5.0" +core_version: "v5.0-185-g8167047" +version_basis: + kind: tag + match: "v*" + tag: "v5.0" + distance: 185 mame_version: "0.106" display_name: "Arcade (AdvanceMAME)" mode: standalone diff --git a/emulators/advmame-0.94.yml b/emulators/advmame-0.94.yml index 7d8c603a2..5e3d38983 100644 --- a/emulators/advmame-0.94.yml +++ b/emulators/advmame-0.94.yml @@ -5,6 +5,11 @@ source: "https://files.retropie.org.uk/archives/advancemame-0.94.0.tar.gz" upstream: "https://www.mamedev.org" profiled_date: "2026-10-20" core_version: "0.94.0" +version_basis: + kind: package + url: "https://files.retropie.org.uk/archives/advancemame-0.94.0.tar.gz" + pattern: 'advancemame-(\d+\.\d+\.\d+)\.tar\.gz' + artifact: "advancemame-0.94.0.tar.gz" mame_version: "0.94" display_name: "Arcade (AdvanceMAME 0.94)" mode: standalone diff --git a/emulators/advmame-1.4.yml b/emulators/advmame-1.4.yml index e8f0a7697..490b994d7 100644 --- a/emulators/advmame-1.4.yml +++ b/emulators/advmame-1.4.yml @@ -6,7 +6,12 @@ upstream: "https://www.mamedev.org" profiled_date: "2026-10-20" source_commit: "237ca5c898e51e1b7a70ce52bccf008aa722e924" pin_frozen: "RetroPie builds the advancemame-1.4 release tarball, whose src/ tree is this tag. Later commits are not part of that build." -core_version: "1.4" +core_version: "advancemame-1.4" +version_basis: + kind: tag + match: "advancemame-*" + tag: "advancemame-1.4" + distance: 0 mame_version: "0.106" display_name: "Arcade (AdvanceMAME 1.4)" mode: standalone diff --git a/emulators/aethersx2.yml b/emulators/aethersx2.yml index ba3a0c004..ae3851eb9 100644 --- a/emulators/aethersx2.yml +++ b/emulators/aethersx2.yml @@ -8,6 +8,11 @@ profiled_date: "2026-08-11" source_commit: "1d1f795dfc70e38da67724c7298779260f513889" upstream_commit: "f0523f8acb1d3a765ee73b74cffec63093569199" core_version: "1.5-3939" +version_basis: + kind: package + url: "https://web.archive.org/web/20230320102332/https://www.aethersx2.com/archive/desktop/mac/AetherSX2-v1.5-3939-mac.zip" + pattern: 'AetherSX2-v([0-9.]+-[0-9]+)-mac\.zip' + artifact: "AetherSX2-v1.5-3939-mac.zip" display_name: "Sony - PlayStation 2 (AetherSX2)" cores: - aethersx2 diff --git a/emulators/ags.yml b/emulators/ags.yml index ff986e7e5..6aa46a1fa 100644 --- a/emulators/ags.yml +++ b/emulators/ags.yml @@ -5,7 +5,11 @@ source: "https://github.com/adventuregamestudio/ags" source_branch: release-3.6.0 source_commit: "6802bad8dc3189462003d4a169fc591f64cfb9b6" profiled_date: "2026-10-20" -core_version: "3.6.0.60" +core_version: "v3.6.0.60" +version_basis: + kind: tag + tag: "v3.6.0.60" + distance: 0 display_name: "Adventure Game Studio (AGS)" cores: - ags diff --git a/emulators/alephone.yml b/emulators/alephone.yml index a44938d6c..d0dfaf1a6 100644 --- a/emulators/alephone.yml +++ b/emulators/alephone.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/Aleph-One-Marathon/alephone" profiled_date: "2026-10-20" source_commit: "07a9c36aff403d143a0608815f725631a01e382c" pin_frozen: "RetroPie, the only platform that ships it, builds the release-20250829 tag at this commit (scriptmodules/ports/alephone.sh, _get_branch_alephone). Debian 10 and older get release-20250302." -core_version: "1.11 (20250829)" +core_version: "release-20250829" +version_basis: + kind: tag + tag: "release-20250829" + distance: 0 display_name: "Marathon (Aleph One)" cores: - alephone diff --git a/emulators/altirra.yml b/emulators/altirra.yml index 6497c0a66..0c8f070e9 100644 --- a/emulators/altirra.yml +++ b/emulators/altirra.yml @@ -8,6 +8,11 @@ version_source: pattern: '<h3>Current version</h3>\s*<p>\s*Altirra (\d+\.\d+)' profiled_date: "2026-08-11" core_version: "4.40" +version_basis: + kind: package + url: "https://www.virtualdub.org/downloads/Altirra-4.40-src.7z" + pattern: 'Altirra-(\d+\.\d+)-src\.7z' + artifact: "Altirra-4.40-src.7z" display_name: "Atari - 400/800/1200XL/XL/XE/XEGS/5200 (Altirra)" cores: [altirra] found_by: content diff --git a/emulators/amiarcadia.yml b/emulators/amiarcadia.yml index bb5400f98..ae85e38d0 100644 --- a/emulators/amiarcadia.yml +++ b/emulators/amiarcadia.yml @@ -6,6 +6,10 @@ upstream: "https://amigan.1emu.net/releases/" profiled_date: "2026-10-23" source_commit: "8ca27c925833fe0021475155512c7f467924f647" core_version: "4.60" +version_basis: + kind: file + path: "DroidArcadia/app/src/main/cpp/da.h" + pattern: '#define\s+INTEGERVERSION\s+"([^"]+)"' display_name: "Arcadia 2001 / Interton VC 4000 (AmiArcadia)" cores: - amiarcadia diff --git a/emulators/amiberry.yml b/emulators/amiberry.yml index 530c5016b..af888bb54 100644 --- a/emulators/amiberry.yml +++ b/emulators/amiberry.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/tonioni/WinUAE" profiled_date: "2026-10-26" source_commit: "49dbd1f027ef2afc12862b30c0c31ac8efa66221" upstream_commit: "15110cf6606d1188800ea7ad86bf1cbd9c688741" -core_version: "v8.4.2" +core_version: "8.4.2" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'project\(amiberry\s+VERSION\s+([0-9][0-9.]*)' display_name: "Commodore - Amiga (Amiberry)" cores: [amiberry, "AMIBERRY"] systems: diff --git a/emulators/anarch.yml b/emulators/anarch.yml index 5d7d80ad2..33b7b5b2c 100644 --- a/emulators/anarch.yml +++ b/emulators/anarch.yml @@ -6,6 +6,10 @@ upstream: "https://gitlab.com/drummyfish/anarch" profiled_date: "2026-03-22" source_commit: "187050344ef440c4eaf3135304a020093564fa3f" core_version: "1.1d" +version_basis: + kind: file + path: "texts.h" + pattern: '#define\s+SFG_VERSION_STRING\s+"([^"]+)"' display_name: "Anarch" cores: [anarch] systems: [] diff --git a/emulators/applewin.yml b/emulators/applewin.yml index 739874686..6aaca4062 100644 --- a/emulators/applewin.yml +++ b/emulators/applewin.yml @@ -6,7 +6,12 @@ upstream: "https://github.com/AppleWin/AppleWin" profiled_date: "2026-03-23" source_commit: "0a89db3d593a74d04590b902fb7206723591f445" upstream_commit: "1f3cadb88d1158c139d2e3a7b864d91836856948" -core_version: "1.31.0.1" +core_version: "1.32.1.0" +version_basis: + kind: file + path: "resource/version.h" + pattern: '#define\s+APPLEWIN_VERSION\s+(\d+),(\d+),(\d+),(\d+)' + format: "{1}.{2}.{3}.{4}" display_name: "Apple II (AppleWin)" cores: - applewin diff --git a/emulators/aps3e.yml b/emulators/aps3e.yml index 8ab2d6ddc..92b387d3c 100644 --- a/emulators/aps3e.yml +++ b/emulators/aps3e.yml @@ -8,7 +8,11 @@ profiled_date: "2026-10-06" source_commit: "c6ca18217f2f1563235f83d94df78e35423a1720" upstream_commit: "1f080485b95db2700c5cf244b1314f73b6cf564e" upstream_frozen: "RPCS3 is vendored whole under app/src/main/cpp/rpcs3 at this commit, the tree the 2.43 release reports as 20071-1f080485." -core_version: "2.43" +core_version: "1.37-47-gc6ca182" +version_basis: + kind: tag + tag: "1.37" + distance: 47 display_name: "Sony - PlayStation 3 (aPS3e)" cores: - aps3e diff --git a/emulators/arcadeduck.yml b/emulators/arcadeduck.yml index 829d83610..1df81f16e 100644 --- a/emulators/arcadeduck.yml +++ b/emulators/arcadeduck.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/stenzek/duckstation" source_commit: "80cdb6da6b51d687192a6346efe4499b10fe4faf" upstream_commit: "526b4a128827ecaef037134095cd95f431b52d06" profiled_date: "2026-10-26" -core_version: "0.6.0" +core_version: "0.6.0-dev" +version_basis: + kind: file + path: "src/scmversion/arcadeduck_version.h" + pattern: '#define\s+ARCADEDUCK_SEMANTIC_VERSION\s+"([^"]+)"' display_name: "Arcade - Sony ZN-1, Namco System 11, Konami GV/GQ (ArcadeDuck)" cores: - arcadeduck diff --git a/emulators/arcadeflashweb.yml b/emulators/arcadeflashweb.yml index 3a3803863..9d2931b9c 100644 --- a/emulators/arcadeflashweb.yml +++ b/emulators/arcadeflashweb.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/aureyoboss/ArcadeFlashWeb" profiled_date: "2026-08-11" source_commit: "5de66e0cd69b48721a094887a28d042f71ddad08" core_version: "1.0.2" +version_basis: + kind: file + path: "src/ArcadeFlashWeb.pro" + pattern: '^VERSION\s*\+?=\s*(\S+)' display_name: "Adobe Flash (ArcadeFlashWeb)" cores: - arcadeflashweb diff --git a/emulators/ardens.yml b/emulators/ardens.yml index f92f21638..3fb3eb951 100644 --- a/emulators/ardens.yml +++ b/emulators/ardens.yml @@ -5,7 +5,11 @@ source: "https://github.com/tiberiusbrown/ardens" upstream: "https://github.com/tiberiusbrown/ardens" profiled_date: "2026-03-23" source_commit: "e811cc6be72c8a802bd3265a84daf4165c177b93" -core_version: "Git" +core_version: "v0.25.12" +version_basis: + kind: tag + tag: "v0.25.12" + distance: 0 display_name: "Arduboy (Ardens)" cores: - ardens diff --git a/emulators/arduous.yml b/emulators/arduous.yml index a74d091bb..c22c42c2e 100644 --- a/emulators/arduous.yml +++ b/emulators/arduous.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/jmaroeder/arduous" profiled_date: "2026-03-23" source_commit: "831b83e67ad46e8c86b8165649ff81bc6fc6c157" core_version: "0.1.0" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'project\(arduous\s+VERSION\s+([0-9][\w.+-]*)' display_name: "Arduboy (Arduous)" cores: - arduous diff --git a/emulators/ares.yml b/emulators/ares.yml index 274cc2eed..be9726309 100644 --- a/emulators/ares.yml +++ b/emulators/ares.yml @@ -4,7 +4,12 @@ source: "https://github.com/ares-emulator/ares" upstream: "https://github.com/ares-emulator/ares" profiled_date: "2026-10-23" source_commit: "d400eee9764fe22a8de0247a52757d2021d0539c" -core_version: "v148" +core_version: "v148-143-gd400eee" +version_basis: + kind: tag + match: "v[0-9]*" + tag: "v148" + distance: 143 display_name: "ares" cores: [ares, "ares-sa"] mode: standalone diff --git a/emulators/armsx1.yml b/emulators/armsx1.yml index a0c75a604..c54c7fc9d 100644 --- a/emulators/armsx1.yml +++ b/emulators/armsx1.yml @@ -7,6 +7,10 @@ upstream: "https://github.com/allkern/psxe" profiled_date: "2026-10-26" source_commit: "d96a5b8ad6ccccb40a431488aa89b06f0318c217" core_version: "0.3.6" +version_basis: + kind: file + path: "android/app/build.gradle" + pattern: 'armsxVersionName\s*=\s*\(project\.findProperty\(.armsx\.versionName.\)\s*\?:\s*.([^\x27"]+).' display_name: "Sony - PlayStation (ARMSX1)" verification: md5 found_by: content diff --git a/emulators/armsx2.yml b/emulators/armsx2.yml index fc62f866e..7db9c5be5 100644 --- a/emulators/armsx2.yml +++ b/emulators/armsx2.yml @@ -7,7 +7,12 @@ upstream: "https://github.com/PCSX2/pcsx2" profiled_date: "2026-10-26" source_commit: "7f9144189c74edcf5a7ab3ba2aa2247635d24047" upstream_commit: "36907f4b70d149b05c2700acae687bedb720a7af" -core_version: "2.9" +core_version: "2.9-5-g7f91441" +version_basis: + kind: tag + match: "[0-9]*" + tag: "2.9" + distance: 5 display_name: "Sony - PlayStation 2 (ARMSX2)" cores: - armsx2 diff --git a/emulators/atari800.yml b/emulators/atari800.yml index 6419902b2..cc18f11af 100644 --- a/emulators/atari800.yml +++ b/emulators/atari800.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/atari800/atari800" profiled_date: "2026-03-23" source_commit: "4e7fbc73765c1a9670c7506616046ad1d4ccda51" upstream_commit: "98cc2dc749867c9c7317a0271ba062a6c797f886" -core_version: "3.1.0" +core_version: "7.0.0" +version_basis: + kind: file + path: "libretro/config.h" + pattern: '#define\s+PACKAGE_VERSION\s+"([^"]+)"' display_name: "Atari - 400/800/600XL/800XL/130XE/5200 (Atari800)" cores: [atari800] systems: [atari-400-800, atari-5200, xegs] diff --git a/emulators/ax360e.yml b/emulators/ax360e.yml index 2dd253705..57b01d8a6 100644 --- a/emulators/ax360e.yml +++ b/emulators/ax360e.yml @@ -8,7 +8,9 @@ profiled_date: "2026-08-11" source_commit: "b8c1838f21761ac463724e24105eda97b990e704" upstream_commit: "dc561e4df578c903087f9bdf56ff61d9ef9f2a93" upstream_frozen: "The xenia-canary tree vendored under app/src/main/cpp/xenia-canary is canary_experimental at this commit." -core_version: "1.18" +core_version: null +version_basis: + kind: none display_name: "Microsoft - Xbox 360 (aX360e)" cores: - ax360e diff --git a/emulators/azahar-sdl.yml b/emulators/azahar-sdl.yml index 3a146374e..126f775b3 100644 --- a/emulators/azahar-sdl.yml +++ b/emulators/azahar-sdl.yml @@ -5,7 +5,11 @@ source: "https://github.com/johndoe6345789/azahar_libretro" profiled_date: "2026-10-22" source_commit: "c8d39853c1ebacc5657e51d601713a09404ca8a7" pin_frozen: "KNULLI, the only platform that ships it, builds this revision (KNULLI package/emulators/azahar/azahar.mk:7 at tag 20260511). Later commits are not part of that build." -core_version: "Git" +core_version: "2122-rc1-178-gc8d3985" +version_basis: + kind: tag + tag: "2122-rc1" + distance: 178 display_name: "Nintendo - 3DS (Azahar SDL2)" mode: standalone cores: ["azahar"] diff --git a/emulators/azahar.yml b/emulators/azahar.yml index 80ce20d67..d0e7debb9 100644 --- a/emulators/azahar.yml +++ b/emulators/azahar.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/azahar-emu/azahar" profiled_date: "2026-10-22" source_commit: "219d743a1e698101fe1ab8bef43e6563126c3c27" core_version: "2126.2" +version_basis: + kind: tag + tag: "2126.2" + distance: 0 display_name: "Nintendo - 3DS (Azahar)" library_name: "Azahar" cores: diff --git a/emulators/azaharplus.yml b/emulators/azaharplus.yml index 107d3f637..27344f222 100644 --- a/emulators/azaharplus.yml +++ b/emulators/azaharplus.yml @@ -5,7 +5,11 @@ source: "https://github.com/AzaharPlus/AzaharPlus" upstream: "https://github.com/AzaharPlus/AzaharPlus" profiled_date: "2026-08-08" source_commit: "cf9068844820f819a6eabbeeeb6a70d546e3e85a" -core_version: "2126.0-A" +core_version: "AZAHAR_PLUS_2126_2_A" +version_basis: + kind: tag + tag: "AZAHAR_PLUS_2126_2_A" + distance: 0 display_name: "Nintendo - 3DS (AzaharPlus)" cores: - azaharplus diff --git a/emulators/b2.yml b/emulators/b2.yml index a2db29b2c..ded3dd144 100644 --- a/emulators/b2.yml +++ b/emulators/b2.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-23" source_commit: "9793f6a8040c416d147003cada29363b955b54e7" upstream_commit: "e1c9b84a9460909d4dc2030ad1d4e050012b1910" core_version: "v0.4" +version_basis: + kind: file + path: "src/libretro/core.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Acorn - BBC Micro (b2)" cores: [b2] systems: diff --git a/emulators/basiliskii.yml b/emulators/basiliskii.yml index 23cf2b01d..718468f7b 100644 --- a/emulators/basiliskii.yml +++ b/emulators/basiliskii.yml @@ -5,6 +5,11 @@ upstream: "https://github.com/cebix/macemu" profiled_date: "2026-08-08" source_commit: "96e512bd6376e78a2869f16dcc8a9028bce5ee72" core_version: "1.0" +version_basis: + kind: file + path: "BasiliskII/src/include/version.h" + pattern: 'const int VERSION_MAJOR = (\d+);\s*\nconst int VERSION_MINOR = (\d+);' + format: "{1}.{2}" display_name: "Apple - Macintosh 68k (Basilisk II)" cores: - basiliskii diff --git a/emulators/bbkemu.yml b/emulators/bbkemu.yml index 608a01b57..82ef784d8 100644 --- a/emulators/bbkemu.yml +++ b/emulators/bbkemu.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/AloysHF/BBKEmu" profiled_date: "2026-10-26" source_commit: "6641863f6ec59a74635753766e3f9d34adf92b05" core_version: "0.1.0" +version_basis: + kind: file + path: "Cargo.toml" + pattern: 'version\s+=\s+"([^"]+)' display_name: "BBK - Electronic Dictionary (BBKEmu)" cores: - bbkemu diff --git a/emulators/beebem.yml b/emulators/beebem.yml index 2ae84f1b7..d0bd0654c 100644 --- a/emulators/beebem.yml +++ b/emulators/beebem.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/stardot/beebem-windows" profiled_date: "2026-08-11" source_commit: "a982ba6a74af09e801c296b29d514dbd4da09b94" core_version: "4.19" +version_basis: + kind: file + path: "Src/Version.h" + pattern: '#define\s+VERSION_STRING\s+"([^"]+)' display_name: "Acorn - BBC Micro (BeebEm)" cores: [beebem] systems: diff --git a/emulators/beetle_gba.yml b/emulators/beetle_gba.yml index 8a1bfc648..ceb11e511 100644 --- a/emulators/beetle_gba.yml +++ b/emulators/beetle_gba.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-03-24" source_commit: "b158166237b17253188cfdbe73a8a0b9fe4b3a8c" core_version: "v0.9.36" +version_basis: + kind: file + path: "libretro.cpp" + pattern: '#define\s+MEDNAFEN_CORE_VERSION\s+"([^"]+)' display_name: "Nintendo - Game Boy Advance (Beetle GBA)" cores: [beetle_gba, mednafen_gba] systems: diff --git a/emulators/beetle_lynx.yml b/emulators/beetle_lynx.yml index cb37f3e14..eeeb118b8 100644 --- a/emulators/beetle_lynx.yml +++ b/emulators/beetle_lynx.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-03-24" source_commit: "fcdefcfb3c11d6d2e71be076a5d3df2e88ab73ed" core_version: "v1.24.0" +version_basis: + kind: file + path: "libretro.cpp" + pattern: '#define\s+MEDNAFEN_CORE_VERSION\s+"([^"]+)' display_name: "Atari - Lynx (Beetle Lynx)" cores: [mednafen_lynx, "beetle-lynx"] systems: [atari-lynx] diff --git a/emulators/beetle_ngp.yml b/emulators/beetle_ngp.yml index 15454f2c3..d752361f3 100644 --- a/emulators/beetle_ngp.yml +++ b/emulators/beetle_ngp.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-03-24" source_commit: "a50d5ac288a81f2104ddf43195a4efdd15c72227" core_version: "v1.29.0.0" +version_basis: + kind: file + path: "libretro.c" + pattern: '#define\s+MEDNAFEN_CORE_VERSION\s+"([^"]+)' display_name: "SNK - Neo Geo Pocket / Color (Beetle NeoPop)" cores: [mednafen_ngp, "beetle-ngp"] systems: [snk-ngp, snk-ngpc] diff --git a/emulators/beetle_pce.yml b/emulators/beetle_pce.yml index e58ae3595..031541321 100644 --- a/emulators/beetle_pce.yml +++ b/emulators/beetle_pce.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-03-24" source_commit: "b96c11e095b6a40a412d2da02766ae1c3f4fd539" core_version: "v1.29.0" +version_basis: + kind: file + path: "libretro.cpp" + pattern: '#define\s+MEDNAFEN_CORE_VERSION\s+"([^"]+)' display_name: "NEC - PC Engine / SuperGrafx / CD (Beetle PCE)" cores: [beetle_pce, mednafen_pce, pce, beetle-pce] systems: [nec-pc-engine] diff --git a/emulators/beetle_pcfx.yml b/emulators/beetle_pcfx.yml index 10bb21a32..e7686a293 100644 --- a/emulators/beetle_pcfx.yml +++ b/emulators/beetle_pcfx.yml @@ -7,6 +7,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-03-24" source_commit: "c1650bad5fbdcc3c3ccd45e29e3983e1ccf16cff" core_version: "v0.9.36.5" +version_basis: + kind: file + path: "libretro.cpp" + pattern: '#define\s+MEDNAFEN_CORE_VERSION\s+"([^"]+)' display_name: "NEC - PC-FX (Beetle PC-FX)" systems: - nec-pcfx diff --git a/emulators/beetle_psx.yml b/emulators/beetle_psx.yml index 79525414b..af4fcd552 100644 --- a/emulators/beetle_psx.yml +++ b/emulators/beetle_psx.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/beetle-psx-libretro" upstream: "https://mednafen.github.io/" profiled_date: "2026-03-29" source_commit: "7fea57a541abb39b8c5035b6261c3e70962d221b" -core_version: "v0.9.44.1" +core_version: "0.9.44.1" +version_basis: + kind: file + path: "libretro_options.h" + pattern: '#define\s+MEDNAFEN_CORE_SETVERSION\s+"([^"]+)"' display_name: "Sony - PlayStation (Beetle PSX)" cores: [beetle_psx, mednafen_psx, mednafen_psx_hw, "beetle-psx"] systems: [sony-playstation] diff --git a/emulators/beetle_saturn.yml b/emulators/beetle_saturn.yml index 2e95a764f..3bd569eb8 100644 --- a/emulators/beetle_saturn.yml +++ b/emulators/beetle_saturn.yml @@ -7,6 +7,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-10-05" source_commit: "2ce77e20a956dc9a67b8d3d527f477b984310feb" core_version: "v1.32.1" +version_basis: + kind: file + path: "libretro.c" + pattern: '#define\s+MEDNAFEN_CORE_VERSION\s+"([^"]+)' display_name: "Sega - Saturn (Beetle Saturn)" cores: - mednafen_saturn diff --git a/emulators/beetle_vb.yml b/emulators/beetle_vb.yml index 64e5d7bc3..a2b1f0355 100644 --- a/emulators/beetle_vb.yml +++ b/emulators/beetle_vb.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/beetle-vb-libretro" upstream: "https://mednafen.github.io/" profiled_date: "2026-03-24" source_commit: "d5ae54c8e23b573a3b34e888b2d48a588027e92c" -core_version: "v0.9.36.1" +core_version: "v1.31.0" +version_basis: + kind: file + path: "libretro.cpp" + pattern: '#define\s+MEDNAFEN_CORE_VERSION\s+"([^"]+)' display_name: "Nintendo - Virtual Boy (Beetle VB)" cores: [mednafen_vb, vb, "beetle-vb"] systems: [nintendo-virtualboy] diff --git a/emulators/beetle_wswan.yml b/emulators/beetle_wswan.yml index 32369125a..258f75b5d 100644 --- a/emulators/beetle_wswan.yml +++ b/emulators/beetle_wswan.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-03-24" source_commit: "4b01295838ea89e3f1355bbe4cb5cf98aa6108cd" core_version: "v0.9.35.1" +version_basis: + kind: file + path: "libretro.c" + pattern: '#define\s+MEDNAFEN_CORE_VERSION\s+"([^"]+)' display_name: "Bandai - WonderSwan/Color (Beetle Wonderswan)" cores: [beetle_wswan, mednafen_wswan, "beetle-wswan"] systems: [bandai-wswan, bandai-wswanc] diff --git a/emulators/bennugd-monolithic.yml b/emulators/bennugd-monolithic.yml index ff6cf19ae..3af70c233 100644 --- a/emulators/bennugd-monolithic.yml +++ b/emulators/bennugd-monolithic.yml @@ -4,7 +4,11 @@ core_classification: game_engine source: "https://github.com/christianhaitian/bennugd-monolithic" profiled_date: "2026-10-22" source_commit: "60ee3389efcf9b402d66035e87f33d17d70cbd83" -core_version: "git" +core_version: "1.0.0" +version_basis: + kind: file + path: "projects/cmake/include/common_defs.cmake" + pattern: '-DVERSION="([^"]+)"' display_name: "Bennu Game Development (bennugd-monolithic)" cores: - "bgdi" diff --git a/emulators/bennugd.yml b/emulators/bennugd.yml index 0f1e2d8c8..26e92666e 100644 --- a/emulators/bennugd.yml +++ b/emulators/bennugd.yml @@ -5,7 +5,11 @@ source: "https://github.com/diekleinekuh/BennuGD_libretro" upstream: "https://github.com/SplinterGU/BennuGD" profiled_date: "2026-03-23" source_commit: "5fba764ac709545d4b0d3b28deff2ec0c7d1a91b" -core_version: "git" +core_version: "1.0.0" +version_basis: + kind: file + path: "core/common/bgd_version.c" + pattern: 'snprintf\(buffer, sizeof\(buffer\), "([0-9][0-9.]*)-BennuGD_libretro' display_name: "Bennu Game Development" cores: - bennugd diff --git a/emulators/bermuda.yml b/emulators/bermuda.yml index aceebc460..491a432e8 100644 --- a/emulators/bermuda.yml +++ b/emulators/bermuda.yml @@ -5,6 +5,10 @@ source: "https://github.com/cyxx/bermuda" profiled_date: "2026-10-22" source_commit: "cf6bdb68d53a1618967da565a44c931b15daf791" core_version: "0.1.7" +version_basis: + kind: file + path: "main_libretro.cpp" + pattern: 'static\s+const\s+char\s+\*kVersion\s+=\s+"([^"]+)' display_name: "Bermuda Syndrome (bs)" cores: - "bs" diff --git a/emulators/bigpemu.yml b/emulators/bigpemu.yml index 7f0ecbf10..7c3d28564 100644 --- a/emulators/bigpemu.yml +++ b/emulators/bigpemu.yml @@ -7,6 +7,12 @@ version_source: pattern: 'Current Version: <strong>([0-9.]+)</strong>' profiled_date: "2026-10-20" core_version: "1.221" +version_basis: + kind: package + url: "https://www.richwhitehouse.com/jaguar/builds/BigPEmu_Linux64_v1221.tar.gz" + pattern: 'BigPEmu_Linux64_v(\d)(\d+)\.tar\.gz' + format: "{1}.{2}" + artifact: "BigPEmu_Linux64_v1221.tar.gz" display_name: "BigPEmu (Atari Jaguar)" cores: - bigpemu diff --git a/emulators/bizhawk.yml b/emulators/bizhawk.yml index 4b0647243..2d727fc13 100644 --- a/emulators/bizhawk.yml +++ b/emulators/bizhawk.yml @@ -5,6 +5,10 @@ source: "https://github.com/TASEmulators/BizHawk" source_commit: "bdddf4a58aa1a022afb11dc73294a81a5aa7bbd5" profiled_date: "2026-10-20" core_version: "2.11.1" +version_basis: + kind: tag + tag: "2.11.1" + distance: 0 display_name: "Multi-system (BizHawk EmuHawk)" cores: - bizhawk diff --git a/emulators/bk.yml b/emulators/bk.yml index c0cef9d72..a761667d7 100644 --- a/emulators/bk.yml +++ b/emulators/bk.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/bk-emulator" upstream: "https://github.com/emestee/bk-emulator" profiled_date: "2026-03-23" source_commit: "92042a753289cedf05e7e6bd8e75849f83e48966" -core_version: "1.00" +core_version: "v1.0" +version_basis: + kind: file + path: "libretro.c" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "Elektronika - BK-0010/BK-0011(M)" cores: - bk diff --git a/emulators/blastem.yml b/emulators/blastem.yml index 8845b94f8..f3d16d286 100644 --- a/emulators/blastem.yml +++ b/emulators/blastem.yml @@ -7,6 +7,10 @@ profiled_date: "2026-10-20" source_commit: "ab743653ed110eeb7b1fe64d00cc5f9279c2bfec" prose_written_at: "1e0de94dc7e669c0925a22c0fccf6cdc837af0a0" core_version: "1.0.1-pre" +version_basis: + kind: file + path: "version.inc" + pattern: '#define\s+BLASTEM_VERSION\s+"([^"]+)' display_name: "Sega - Mega Drive - Genesis (BlastEm)" cores: - blastem diff --git a/emulators/bluemsx.yml b/emulators/bluemsx.yml index b5b78c22e..b510ba90f 100644 --- a/emulators/bluemsx.yml +++ b/emulators/bluemsx.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/blueMSX-libretro" upstream: "http://bluemsx.msxblue.com/" profiled_date: "2026-03-23" source_commit: "e3086eb5d36d77fa11704cf53dc176686e70127d" -core_version: "SVN" +core_version: "2.8.3" +version_basis: + kind: file + path: "Src/BuildInfo/version.h" + pattern: '#define\s+BLUE_MSX_VERSION\s+"([^"]+)"' display_name: "MSX/SVI/ColecoVision/SG-1000 (blueMSX)" cores: - bluemsx diff --git a/emulators/bnes.yml b/emulators/bnes.yml index 1dc180c51..7914e69f7 100644 --- a/emulators/bnes.yml +++ b/emulators/bnes.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/Sir-Walrus/bsnes-gc" profiled_date: "2026-03-23" source_commit: "8e26e89a93bef8eb8992d1921b539dce1792660a" core_version: "v083" +version_basis: + kind: file + path: "libretro/libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Nintendo - NES / Famicom (bnes)" cores: - bnes diff --git a/emulators/boom3.yml b/emulators/boom3.yml index 6e0fe58ea..251256c5c 100644 --- a/emulators/boom3.yml +++ b/emulators/boom3.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/dhewm/dhewm3" profiled_date: "2026-03-23" source_commit: "efe140ce8fdf8793f5a6fbba062fb34df7f55a81" upstream_commit: "455b88e8dff2be822f08eb498f51b383e851fa38" -core_version: "git" +core_version: "1.5.5" +version_basis: + kind: file + path: "neo/framework/Licensee.h" + pattern: '#define\s+ENGINE_VERSION\s+"dhewm3 ([^"]+)"' display_name: "Doom 3 (boom3)" cores: [boom3, boom3_xp] systems: [doom3] diff --git a/emulators/boytacean.yml b/emulators/boytacean.yml index c1e2a6ded..90f0d912f 100644 --- a/emulators/boytacean.yml +++ b/emulators/boytacean.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/joamag/boytacean" profiled_date: "2026-03-23" source_commit: "4d806d0770f117cc8e6ac0fe75b95aa9dc39fc4f" core_version: "0.13.2" +version_basis: + kind: file + path: "setup.py" + pattern: 'version="([^"]+)' display_name: "Nintendo - Game Boy / Color (Boytacean)" cores: - boytacean diff --git a/emulators/bsnes-jg.yml b/emulators/bsnes-jg.yml index c24b7692e..4fc53e8b2 100644 --- a/emulators/bsnes-jg.yml +++ b/emulators/bsnes-jg.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-23" source_commit: "4aef191fef72be539ccc07ada21c6e0a65360eb7" upstream_commit: "53e6a7c2ec4b4220adc2f8dcb3786489bd04fe0e" core_version: "2.1.2" +version_basis: + kind: file + path: "version.h" + pattern: '#define\s+JG_VERSION\s+"([^"]+)' display_name: "Nintendo - SNES / SFC (bsnes-jg)" cores: [bsnes-jg, bsnes_jg] systems: diff --git a/emulators/bsnes.yml b/emulators/bsnes.yml index 0c0b74ab2..ef31dc4a2 100644 --- a/emulators/bsnes.yml +++ b/emulators/bsnes.yml @@ -8,6 +8,10 @@ profiled_date: "2026-04-05" source_commit: "05439f96121d2b9d7ad7a5fc1f29d7eebdcc8c43" upstream_commit: "78474e5d39f58872dc21aca18cf9eb583b147fe7" core_version: "115" +version_basis: + kind: file + path: "bsnes/emulator/emulator.hpp" + pattern: 'static const string Version\s*=\s*"([^"]+)"' display_name: "Nintendo - SNES / SFC (bsnes)" cores: [bsnes] systems: [nintendo-snes, nintendo-super-game-boy, nintendo-satellaview] diff --git a/emulators/bsnes2014.yml b/emulators/bsnes2014.yml index cf0a8146f..58efca237 100644 --- a/emulators/bsnes2014.yml +++ b/emulators/bsnes2014.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/bsnes-emu/bsnes" profiled_date: "2026-03-25" source_commit: "3c1394e042ee444c8248e1b9210e14ea55e836e9" upstream_commit: "78474e5d39f58872dc21aca18cf9eb583b147fe7" -core_version: "v094" +core_version: "094" +version_basis: + kind: file + path: "emulator/emulator.hpp" + pattern: 'static const char Version\[\]\s*=\s*"([^"]+)"' display_name: "Nintendo - SNES / SFC (bsnes 2014)" cores: [bsnes2014_accuracy, bsnes2014_balanced, bsnes2014_performance] systems: diff --git a/emulators/bsnes_cplusplus98.yml b/emulators/bsnes_cplusplus98.yml index e67ca0899..ac8da33a5 100644 --- a/emulators/bsnes_cplusplus98.yml +++ b/emulators/bsnes_cplusplus98.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/bsnes-libretro-cplusplus98" upstream: "https://byuu.org/" profiled_date: "2026-03-23" source_commit: "baec09aa4796b7575aba1c1ae7335f493c2216af" -core_version: "v085 (Performance)" +core_version: "v085" +version_basis: + kind: file + path: "snes/libretro/libretro.cpp" + pattern: 'static string version\("(v[0-9]+)' display_name: "Nintendo - SNES / SFC (bsnes C++98 (v085))" cores: [bsnes_cplusplus98] systems: diff --git a/emulators/bsnes_hd_beta.yml b/emulators/bsnes_hd_beta.yml index 32f9f80b9..0b9bbcd0d 100644 --- a/emulators/bsnes_hd_beta.yml +++ b/emulators/bsnes_hd_beta.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/bsnes-emu/bsnes" profiled_date: "2026-03-23" source_commit: "fc26b25ea236f0f877f0265d2a2c37dfd93dfde9" upstream_commit: "78474e5d39f58872dc21aca18cf9eb583b147fe7" -core_version: "v10.6" +core_version: "10.6" +version_basis: + kind: file + path: "bsnes/emulator/emulator.hpp" + pattern: 'static const string Version\s*=\s*"([^"]+)"' display_name: "Nintendo - SNES / SFC (bsnes-hd beta)" cores: [bsnes_hd_beta, bsneshd, bsnes_hd] systems: diff --git a/emulators/bsnes_mercury.yml b/emulators/bsnes_mercury.yml index 353f1e6cc..9f62a4fd1 100644 --- a/emulators/bsnes_mercury.yml +++ b/emulators/bsnes_mercury.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/bsnes-mercury" upstream: "https://byuu.org/higan" profiled_date: "2026-03-25" source_commit: "79d7f9de218b6ffa65a80bbdc5828532bc239232" -core_version: "v094 (Mercury)" +core_version: "094" +version_basis: + kind: file + path: "emulator/emulator.hpp" + pattern: 'static const char Version\[\]\s*=\s*"([^"]+)"' display_name: "Nintendo - SNES / SFC (bsnes-mercury)" cores: [bsnes_mercury_accuracy, bsnes_mercury_balanced, bsnes_mercury_performance] systems: diff --git a/emulators/bstone.yml b/emulators/bstone.yml index 643dd76a7..d7f4dbb2e 100644 --- a/emulators/bstone.yml +++ b/emulators/bstone.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/bibendovsky/bstone" profiled_date: "2026-10-04" source_commit: "e65a6b40b960a409d7ea840580c2431f56fb6fd4" core_version: "v1.3.4" +version_basis: + kind: tag + tag: "v1.3.4" + distance: 0 display_name: "Blake Stone (BStone)" cores: [bstone] systems: [blake-stone] diff --git a/emulators/bsyndrome.yml b/emulators/bsyndrome.yml index 7fa271a45..48021079f 100644 --- a/emulators/bsyndrome.yml +++ b/emulators/bsyndrome.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/cyxx/bermuda" source_commit: "c3aaa0337daca116eab5804456673bd01396bbb4" profiled_date: "2026-10-20" core_version: "0.1.7" +version_basis: + kind: tag + tag: "0.1.7" + distance: 0 display_name: "Bermuda Syndrome (bs)" cores: [bsyndrome] systems: [bsyndrome] diff --git a/emulators/c64-emu.yml b/emulators/c64-emu.yml index f437bcfb3..91c6a7db3 100644 --- a/emulators/c64-emu.yml +++ b/emulators/c64-emu.yml @@ -7,6 +7,10 @@ profiled_date: "2026-08-11" source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" upstream_commit: "46b1bc4393251f838ce3dadd241c1f567d9371d1" core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/CMakeLists.txt" + pattern: 'project\(\s*EmuFramework\s+VERSION\s+([0-9.]+)' display_name: "Commodore - C64 (C64.emu)" mode: standalone cores: diff --git a/emulators/cannonball.yml b/emulators/cannonball.yml index 9e0a1ebf6..13cc17e12 100644 --- a/emulators/cannonball.yml +++ b/emulators/cannonball.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/djyt/cannonball" profiled_date: "2026-03-23" source_commit: "0d83575d920ea4c0a280847a19d7802f673e6a68" upstream_commit: "27493ebf62be3498dff93ed6a45e8e2db819bae1" -core_version: "1.0" +core_version: "0.3" +version_basis: + kind: file + path: "src/main/frontend/menu.c" + pattern: 'menu_about\[[^\]]+\]\s*=\s*"CANNONBALL ([0-9.]+) ' display_name: "Cannonball" cores: - cannonball diff --git a/emulators/cap32.yml b/emulators/cap32.yml index ef710fdf7..fad619729 100644 --- a/emulators/cap32.yml +++ b/emulators/cap32.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/ColinPitrat/caprice32" profiled_date: "2026-10-23" source_commit: "8e61dd69d948cea16c3bad734f7b9d0c2a018cc8" upstream_commit: "8c778bf072a06fb7c23b9cccd179041db7f79a52" -core_version: "v4.5.4" +core_version: "4.5.4" +version_basis: + kind: file + path: "libretro/libretro-core.h" + pattern: '#define\s+VERSION_STRING\s+"([^"]+)"' display_name: "Amstrad - CPC/GX4000 (Caprice32)" cores: - cap32 diff --git a/emulators/capriceforever.yml b/emulators/capriceforever.yml index 0abad5171..aa49293db 100644 --- a/emulators/capriceforever.yml +++ b/emulators/capriceforever.yml @@ -5,6 +5,10 @@ source: "https://www.retrobat.org/repo/win64/stable/emulators/capriceforever.7z" upstream: closed-source profiled_date: "2026-10-20" core_version: "26.4" +version_basis: + kind: package + url: "https://www.retrobat.org/repo/win64/stable/emulators/capriceforever.7z" + artifact: "capriceforever.7z, Caprice.exe version resource ProductVersion" display_name: "Amstrad - CPC / PLUS (CaPriCe Forever)" cores: - capriceforever diff --git a/emulators/capricerpi.yml b/emulators/capricerpi.yml index 31d354280..75743e032 100644 --- a/emulators/capricerpi.yml +++ b/emulators/capricerpi.yml @@ -5,7 +5,11 @@ source: "https://github.com/KaosOverride/CapriceRPI" upstream: "https://sourceforge.net/projects/caprice32/" source_commit: "7d86ebdc6a5e645220c6f30cf407ac57c3256054" profiled_date: "2026-10-20" -core_version: "1.3c" +core_version: "V1.3d" +version_basis: + kind: file + path: "src/cap32.h" + pattern: '#define\s+VERSION_STRING\s+"\s*(V[0-9][^ ]*)' display_name: "Amstrad - CPC (CapriceRPI)" cores: - capricerpi diff --git a/emulators/catacombgl.yml b/emulators/catacombgl.yml index 44d52027e..051201f8e 100644 --- a/emulators/catacombgl.yml +++ b/emulators/catacombgl.yml @@ -6,6 +6,11 @@ upstream: "https://github.com/ArnoAnsems/CatacombGL" profiled_date: "2026-10-04" source_commit: "d11ba549382278cbc67ba6171faf8af338e29f77" core_version: "0.5.7 Beta" +version_basis: + kind: file + path: "src/Engine/EngineCore.cpp" + pattern: 'versionMajor\s*=\s*(\d+);\s*\n.*versionMinor\s*=\s*(\d+);\s*\n.*versionLevel\s*=\s*(\d+);\s*\n.*versionPhase\s*=\s*"([^"]+)"' + format: "{1}.{2}.{3} {4}" display_name: "Catacomb 3-D (CatacombGL)" cores: [catacombgl] systems: [catacomb-3d, catacomb-adventure] diff --git a/emulators/ccleste.yml b/emulators/ccleste.yml index 716025b45..2422cc459 100644 --- a/emulators/ccleste.yml +++ b/emulators/ccleste.yml @@ -4,7 +4,11 @@ core_classification: game_engine source: "https://github.com/lemon32767/ccleste" profiled_date: "2026-10-22" source_commit: "261d96f15af430b8111abc7a5250229246654f52" -core_version: "git" +core_version: "v1.4.0" +version_basis: + kind: tag + tag: "v1.4.0" + distance: 0 display_name: "Celeste Classic (ccleste)" cores: - "ccleste" diff --git a/emulators/cdi2015.yml b/emulators/cdi2015.yml index e703ab99e..4ee554e2a 100644 --- a/emulators/cdi2015.yml +++ b/emulators/cdi2015.yml @@ -6,14 +6,19 @@ upstream: "https://github.com/mamedev/mame/tree/mame0160" profiled_date: "2026-03-23" source_commit: "7adbf440d5f554097f58f8c6ebb673adc4320a31" upstream_commit: "0147bb4cc82e642cf75151f039f240eb20989fbc" -core_version: "0.160" +core_version: "0.159" +version_basis: + kind: file + path: "src/version.c" + pattern: '#define\s+BARE_BUILD_VERSION\s+"([^"]+)"' display_name: "Philips CDi (CDi 2015)" cores: [cdi2015] systems: - philips-cdi notes: | - MAME 0.160 compiled with SUBTARGET=cdi, only cdimono1 driver. + MAME 0.159 (version.c, the core reports 0.160) compiled with SUBTARGET=cdi, + only cdimono1 driver. Checks cdimono1.zip existence in system_dir, then game dir. Returns -2 if missing. cdic.bin and slave.bin are undumped 68HC05 MCUs (NO_DUMP), not in the ZIP. diff --git a/emulators/cdogs.yml b/emulators/cdogs.yml index fd0acf3da..679a2eb5b 100644 --- a/emulators/cdogs.yml +++ b/emulators/cdogs.yml @@ -6,6 +6,11 @@ upstream: "https://github.com/cxong/cdogs-sdl" profiled_date: "2026-10-27" source_commit: "c70d1feaf9d89cf80e23265b256d9a364848e6ea" core_version: "2.5.0" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'set\(VERSION_MAJOR "(\d+)"\)\s*\nset\(VERSION_MINOR "(\d+)"\)\s*\nset\(VERSION_PATCH "(\d+)"\)' + format: "{1}.{2}.{3}" display_name: "C-Dogs" cores: [cdogs, cdogs-sdl] systems: [] diff --git a/emulators/cemu.yml b/emulators/cemu.yml index 6e82bce28..ee4b06a24 100644 --- a/emulators/cemu.yml +++ b/emulators/cemu.yml @@ -8,7 +8,11 @@ logo: "https://raw.githubusercontent.com/cemu-project/Cemu/main/dist/linux/info. profiled_date: "2026-10-23" source_commit: "14f56b569b3668db01a4972225993abd3e8f2096" upstream_commit: "42876aa86d2b92f9c620a76959a792bf392b89d3" -core_version: "2.6" +core_version: "2.6-372-g29f2f1fa" +version_basis: + kind: file + path: "src/libretro/CemuLibretro.cpp" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "Nintendo - Wii U (Cemu)" library_name: "Cemu" save_folder_once: true diff --git a/emulators/cgenius.yml b/emulators/cgenius.yml index a94708f0c..4ca0e5e17 100644 --- a/emulators/cgenius.yml +++ b/emulators/cgenius.yml @@ -5,7 +5,11 @@ source: "https://gitlab.com/Dringgstein/Commander-Genius" upstream: "https://gitlab.com/Dringgstein/Commander-Genius" profiled_date: "2026-10-27" source_commit: "58a3c4fd0782fa2a087e38a039599b2ecf69ccc9" -core_version: "v3.6.4" +core_version: "3.6.4-Release" +version_basis: + kind: file + path: "version.h" + pattern: '#define\s+CGVERSION\s+"([^"]+)"' display_name: "Commander Genius" cores: [cgenius, "CGeniusExe"] systems: [commander-keen] diff --git a/emulators/chailove.yml b/emulators/chailove.yml index ad9a865e3..311b0d585 100644 --- a/emulators/chailove.yml +++ b/emulators/chailove.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/libretro/libretro-chailove" profiled_date: "2026-03-23" source_commit: "524ef951abbd07464830ee12a3f6f5e2aba9efd3" core_version: "2.0.0" +version_basis: + kind: file + path: "src/ChaiLove.h" + pattern: '#define\s+CHAILOVE_VERSION_STRING\s+"([^"]+)' display_name: "ChaiLove" cores: [chailove] systems: [] diff --git a/emulators/chihiro-ds.yml b/emulators/chihiro-ds.yml index f5866a55a..1a0c0d505 100644 --- a/emulators/chihiro-ds.yml +++ b/emulators/chihiro-ds.yml @@ -5,6 +5,10 @@ source: "https://www.retrobat.org/repo/win64/stable/emulators/chihiro-ds.7z" upstream: closed-source profiled_date: "2026-10-20" core_version: "1.0 (Mar 14 2025)" +version_basis: + kind: package + url: "https://www.retrobat.org/repo/win64/stable/emulators/chihiro-ds.7z" + artifact: "chihiro-ds.7z, build string in cxbx.exe and cxbxr-emu.dll" display_name: "Sega - Chihiro (Chihiro-DS)" cores: - chihiro-gun diff --git a/emulators/chimerasnes.yml b/emulators/chimerasnes.yml index 5641c312c..30c5554d7 100644 --- a/emulators/chimerasnes.yml +++ b/emulators/chimerasnes.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/snes9xgit/snes9x" profiled_date: "2026-03-23" source_commit: "04c57c2902c25f36ae5a5d9c57aff851a772c868" upstream_commit: "1bcc369e89f08243e0a462882fb1f3e42e51de3a" -core_version: "" +core_version: "86bab70_20231001-4-g04c57c2" +version_basis: + kind: tag + tag: "86bab70_20231001" + distance: 4 display_name: "Nintendo - SNES / SFC (ChimeraSNES)" cores: [chimerasnes] systems: diff --git a/emulators/chocolate-doom.yml b/emulators/chocolate-doom.yml index 2cd08418f..b3f416c2e 100644 --- a/emulators/chocolate-doom.yml +++ b/emulators/chocolate-doom.yml @@ -6,6 +6,10 @@ profiled_date: "2026-10-22" source_commit: "72d9e9318c4ccc61dab29bb9cc30bc8a9a93266d" pin_frozen: "EmuELEC, the only platform that ships it, builds this revision (EmuELEC packages/sx05re/emuelec-ports/chocolate-doom/package.mk:5). Later commits are not part of that build." core_version: "3.0.0" +version_basis: + kind: file + path: "configure.ac" + pattern: 'AC_INIT\(Chocolate\s+Doom,\s+([0-9][\w.+-]*)' display_name: "Doom (Chocolate Doom)" cores: - "Chocolate-Doom" diff --git a/emulators/citra-mmj.yml b/emulators/citra-mmj.yml index 3a079f61e..a9458d166 100644 --- a/emulators/citra-mmj.yml +++ b/emulators/citra-mmj.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/weihuoya/citra" profiled_date: "2026-08-11" source_commit: "9198dc24df2eb534b8fe7fa1c5c457081a7244ab" core_version: "20251112" +version_basis: + kind: tag + tag: "20251112" + distance: 0 display_name: "Nintendo - 3DS (Citra MMJ)" cores: - citra-mmj diff --git a/emulators/citra.yml b/emulators/citra.yml index 6aa87cb52..8d721e6b9 100644 --- a/emulators/citra.yml +++ b/emulators/citra.yml @@ -5,7 +5,9 @@ source: "https://github.com/libretro/citra" upstream: "https://github.com/citra-emu/citra" profiled_date: "2026-03-23" source_commit: "a0483e9abe8134ae6b290cdca7d49cb77689f05b" -core_version: "Git" +core_version: null +version_basis: + kind: none display_name: "Nintendo - 3DS (Citra)" library_name: "Citra" cores: [citra] diff --git a/emulators/citra2018.yml b/emulators/citra2018.yml index 21a9237a0..3e78e60a7 100644 --- a/emulators/citra2018.yml +++ b/emulators/citra2018.yml @@ -5,7 +5,9 @@ source: "https://github.com/libretro/citra2018" upstream: "https://github.com/citra-emu/citra" profiled_date: "2026-03-23" source_commit: "95e2f06c179c8daf44fa344c206f549cf332d21b" -core_version: "Git" +core_version: null +version_basis: + kind: none display_name: "Nintendo - 3DS (Citra 2018)" library_name: "Citra2018" cores: [citra2018] diff --git a/emulators/citra_canary.yml b/emulators/citra_canary.yml index 4acc1471b..89df6d0f7 100644 --- a/emulators/citra_canary.yml +++ b/emulators/citra_canary.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/citra-emu/citra" profiled_date: "2026-03-23" source_commit: "5401990a9be46e4497abc92db3d5f2042674303d" source_branch: canary -core_version: "Git" +core_version: "canary-82-6-g5401990" +version_basis: + kind: tag + tag: "canary-82" + distance: 6 display_name: "Nintendo - 3DS (Citra Canary/Experimental)" library_name: "Citra Canary" cores: [citra_canary] diff --git a/emulators/citron.yml b/emulators/citron.yml index 2ff13f8f5..d4b5a25ed 100644 --- a/emulators/citron.yml +++ b/emulators/citron.yml @@ -6,6 +6,9 @@ upstream: "https://git.citron-emu.org/citron-emu/Citron" profiled_date: "2026-03-26" upstream_gone: "git.citron-emu.org no longer resolves, and git.citron-emu.com redirects to an unrelated survey site, the domain having been taken. Observed 2026-09-04, no mirror found." core_version: "2026.03.12" +version_basis: + kind: unverified + why: host_gone display_name: "Citron (Nintendo Switch)" cores: - citron diff --git a/emulators/clk.yml b/emulators/clk.yml index fc04a8c9b..a0259ca14 100644 --- a/emulators/clk.yml +++ b/emulators/clk.yml @@ -4,7 +4,11 @@ source: "https://github.com/TomHarte/CLK" upstream: "https://github.com/TomHarte/CLK" profiled_date: "2026-03-26" source_commit: "9020107b563b68595ffdb6ef18aacdec85c78d69" -core_version: "2026-07-28" +core_version: "2026-07-23-136-g9020107" +version_basis: + kind: tag + tag: "2026-07-23" + distance: 136 display_name: "Clock Signal" cores: [clk] systems: diff --git a/emulators/clownmdemu.yml b/emulators/clownmdemu.yml index cacf2a6d3..27120a342 100644 --- a/emulators/clownmdemu.yml +++ b/emulators/clownmdemu.yml @@ -7,7 +7,11 @@ profiled_date: "2026-03-23" source_commit: "d43c2708b0a31c285ce16724b6c4a2e92af07346" # The core the port vendors at source_commit (common -> core submodule). upstream_commit: "88ef45a6585556e2247dd26b6c937d6b9fb4a12d" -core_version: "Git" +core_version: "v1.6.12" +version_basis: + kind: file + path: "source/libretro-interface.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "Sega - MD/CD (ClownMDEmu)" cores: - clownmdemu diff --git a/emulators/colem.yml b/emulators/colem.yml index e13f8f719..c958b3368 100644 --- a/emulators/colem.yml +++ b/emulators/colem.yml @@ -8,6 +8,12 @@ version_source: pattern: 'The Latest Version of ColEm is (\d+(?:\.\d+)+)' profiled_date: "2026-08-08" core_version: "5.6" +version_basis: + kind: package + url: "https://fms.komkon.org/ColEm/ColEm56-Source.zip" + pattern: 'ColEm(\d)(\d+)-Source\.zip' + format: "{1}.{2}" + artifact: "ColEm56-Source.zip" display_name: "Coleco - ColecoVision / Adam (ColEm)" cores: - colem diff --git a/emulators/coolbaremu.yml b/emulators/coolbaremu.yml index 9894753eb..2bd331cc1 100644 --- a/emulators/coolbaremu.yml +++ b/emulators/coolbaremu.yml @@ -5,7 +5,11 @@ source: "https://github.com/AloysHF/CoolbarEmu" upstream: "https://github.com/AloysHF/CoolbarEmu" profiled_date: "2026-10-17" source_commit: "88e90440daab0bdc7bc141728b51841e0c730528" -core_version: "0.2.0" +core_version: "v0.2.0" +version_basis: + kind: tag + tag: "v0.2.0" + distance: 0 display_name: "Coolbar (CoolbarEmu)" cores: - "coolbaremu" diff --git a/emulators/coolcv.yml b/emulators/coolcv.yml index b0927cec8..2a8920e4a 100644 --- a/emulators/coolcv.yml +++ b/emulators/coolcv.yml @@ -5,6 +5,10 @@ source: "https://files.retropie.org.uk/archives/coolcv.tar.gz" upstream: "http://nanochess.org/" profiled_date: "2026-10-20" core_version: "0.6.2" +version_basis: + kind: package + url: "https://files.retropie.org.uk/archives/coolcv.tar.gz" + artifact: "coolcv.tar.gz, latest entry of coolcv.txt" display_name: "Coleco - ColecoVision / Adam (CoolCV)" cores: - coolcv diff --git a/emulators/corsixth.yml b/emulators/corsixth.yml index 06b6dc9cf..e5a4f5009 100644 --- a/emulators/corsixth.yml +++ b/emulators/corsixth.yml @@ -5,7 +5,11 @@ source: "https://github.com/CorsixTH/CorsixTH" upstream: ~ profiled_date: "2026-10-04" source_commit: "e5668b9b2a6f59c492b2446821528d67f5d0ee53" -core_version: "0.70.1" +core_version: "v0.70.1-263-ge5668b9" +version_basis: + kind: tag + tag: "v0.70.1" + distance: 263 display_name: "Theme Hospital (CorsixTH)" cores: [corsixth] systems: [theme-hospital] diff --git a/emulators/cpcemu.yml b/emulators/cpcemu.yml index 4ef0637dd..d98a99f02 100644 --- a/emulators/cpcemu.yml +++ b/emulators/cpcemu.yml @@ -8,6 +8,11 @@ version_source: pattern: 'CPCemu (\d+(?:\.\d+)+) released' profiled_date: "2026-08-08" core_version: "3.0.2" +version_basis: + kind: package + url: "https://cpc-emu.org/Release/2025-04-24/cpcemu_portable-win32-x86-3.0.2.zip" + pattern: 'cpcemu_portable-win32-x86-(\d+(?:\.\d+)+)\.zip' + artifact: "cpcemu_portable-win32-x86-3.0.2.zip" display_name: "Amstrad - CPC (CPCemu)" cores: - cpcemu diff --git a/emulators/craft.yml b/emulators/craft.yml index 246db0dab..a3b3c78a3 100644 --- a/emulators/craft.yml +++ b/emulators/craft.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/Craft" upstream: "https://github.com/fogleman/Craft" profiled_date: "2026-03-23" source_commit: "f30e7b4b1d1406c750a504583adf0cc88449a699" -core_version: "v1" +core_version: "v1.0-353-gf30e7b4" +version_basis: + kind: tag + tag: "v1.0" + distance: 353 display_name: "Minecraft (Craft)" cores: [craft] systems: [] diff --git a/emulators/crocods.yml b/emulators/crocods.yml index 102683af6..d0dd82be7 100644 --- a/emulators/crocods.yml +++ b/emulators/crocods.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/libretro-crocods" upstream: "https://github.com/redbug26/crocods-core" profiled_date: "2026-03-23" source_commit: "a9c63b29443715ae2add392010fca4eae7f93e67" -core_version: "v1" +core_version: "2024-10-16" +version_basis: + kind: file + path: "crocods-core/crocods.h" + pattern: '#define\s+CROCOVERSION\s+"([^"]+)"' display_name: "Amstrad - CPC (CrocoDS)" cores: - crocods diff --git a/emulators/cruzes.yml b/emulators/cruzes.yml index 8214d4920..eea7783c2 100644 --- a/emulators/cruzes.yml +++ b/emulators/cruzes.yml @@ -5,6 +5,10 @@ source: "https://github.com/libretro/libretro-samples/tree/master/tests/cruzes" profiled_date: "2026-03-23" source_commit: "7c2ad112d7a5176de2191e473369668da8946b16" core_version: "0.1" +version_basis: + kind: file + path: "tests/cruzes/cruzes.c" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "Cruzes" cores: - cruzes diff --git a/emulators/cspect.yml b/emulators/cspect.yml index c203099b6..fde57e9e5 100644 --- a/emulators/cspect.yml +++ b/emulators/cspect.yml @@ -8,6 +8,10 @@ version_source: pattern: '<u>v(\d+(?:\.\d+)+)</u>' profiled_date: "2026-08-11" core_version: "3.3.1.0" +version_basis: + kind: package + url: "https://mdf200.itch.io/cspect" + artifact: "CSpect zip from itch.io, CSpect.exe and ReadMe.txt" display_name: "Sinclair - ZX Spectrum Next (#CSpect)" verification: existence cores: [cspect] diff --git a/emulators/cxbx-reloaded-2023.yml b/emulators/cxbx-reloaded-2023.yml index cbab84656..b213b70e2 100644 --- a/emulators/cxbx-reloaded-2023.yml +++ b/emulators/cxbx-reloaded-2023.yml @@ -5,6 +5,10 @@ source: "https://github.com/Cxbx-Reloaded/Cxbx-Reloaded" profiled_date: "2026-10-20" source_commit: "31ff15ba1d91a9a00221546c665efb133889f53a" core_version: "CI-31ff15b" +version_basis: + kind: tag + tag: "CI-31ff15b" + distance: 0 display_name: "Microsoft - Xbox / Sega Chihiro (Cxbx-Reloaded 31ff15b)" cores: - chihiro diff --git a/emulators/cxbx-reloaded.yml b/emulators/cxbx-reloaded.yml index 7ff643890..e7716e748 100644 --- a/emulators/cxbx-reloaded.yml +++ b/emulators/cxbx-reloaded.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/Cxbx-Reloaded/Cxbx-Reloaded" profiled_date: "2026-08-11" source_commit: "585c49a50af1255ab155099e06f24505f9c5a800" core_version: "CI-585c49a" +version_basis: + kind: tag + tag: "CI-585c49a" + distance: 0 display_name: "Microsoft - Xbox / Sega Chihiro (Cxbx-Reloaded)" cores: - cxbx-reloaded diff --git a/emulators/daedalusx64.yml b/emulators/daedalusx64.yml index b465f1c2c..526976ff1 100644 --- a/emulators/daedalusx64.yml +++ b/emulators/daedalusx64.yml @@ -5,7 +5,11 @@ source: "https://github.com/DaedalusX64/daedalus" profiled_date: "2026-10-17" source_commit: "f17e9ed86f3806fadeb69abd29c9526ab2d4bd1b" pin_frozen: "ROCKNIX 20261001 builds this revision. Later upstream commits are not part of that build." -core_version: "Git" +core_version: "1.1.8-837-gf17e9ed" +version_basis: + kind: tag + tag: "1.1.8" + distance: 837 display_name: "Nintendo - 64 (DaedalusX64)" cores: - "daedalusx64" diff --git a/emulators/daphne.yml b/emulators/daphne.yml index b1fbca2a4..b31bbcb45 100644 --- a/emulators/daphne.yml +++ b/emulators/daphne.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/daphne" upstream: "https://github.com/mirror/daphne-emu" profiled_date: "2026-03-23" source_commit: "6f1695dd1f376060666eec0a416ff56bb6c9cccc" -core_version: "Git" +core_version: "1.0.7" +version_basis: + kind: file + path: "daphne/daphne-1.0-src/daphne.cpp" + pattern: 'get_daphne_version\(\)\s*\{\s*return "([^"]+)"' display_name: "Arcade (Daphne)" cores: - daphne diff --git a/emulators/darkplaces.yml b/emulators/darkplaces.yml index 5d9e56e45..f0a8655c8 100644 --- a/emulators/darkplaces.yml +++ b/emulators/darkplaces.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/xonotic/darkplaces" source_branch: div0-stable profiled_date: "2026-10-20" source_commit: "ddabe55ae766087df0b82d214ca4b6d79a443345" -core_version: "div0-stable" +core_version: "xonotic-v0.8.6-2-gddabe55" +version_basis: + kind: tag + tag: "xonotic-v0.8.6" + distance: 2 display_name: "Quake (DarkPlaces)" cores: - darkplaces-quake diff --git a/emulators/demul.yml b/emulators/demul.yml index 0664138f5..25227d87f 100644 --- a/emulators/demul.yml +++ b/emulators/demul.yml @@ -6,6 +6,9 @@ version_source: pattern: '<div class="normaltext">\[[^\]]*\] DEmul (\d+\.\d+)' profiled_date: "2026-03-26" core_version: "0.7" +version_basis: + kind: unverified + why: no_artifact display_name: "Sega - Dreamcast/NAOMI/Hikaru (Demul)" cores: - demul diff --git a/emulators/desmume.yml b/emulators/desmume.yml index 717e2702b..6d1dbbafb 100644 --- a/emulators/desmume.yml +++ b/emulators/desmume.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/TASEmulators/desmume" profiled_date: "2026-03-23" source_commit: "95b4d798731caa809125b6c3c11d17cc332ff6ef" upstream_commit: "e06d11f6df8c2e35d570412c45f5a63e5e7c031d" -core_version: "SVN" +core_version: "0.9.12" +version_basis: + kind: file + path: "desmume/src/version.cpp" + pattern: '#define\s+DESMUME_VERSION_STRING\s+" "\s+"([^"]+)"' display_name: "Nintendo - DS (DeSmuME)" cores: [desmume] systems: [nintendo-ds] diff --git a/emulators/desmume2015.yml b/emulators/desmume2015.yml index f0f213b8b..0c607bf75 100644 --- a/emulators/desmume2015.yml +++ b/emulators/desmume2015.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/TASEmulators/desmume" profiled_date: "2026-03-23" source_commit: "422b688009ccb9f2917c086a8fe79c8cecb030ae" upstream_commit: "fc504ee0bc9ac3434cafcaae7b129c025499a609" -core_version: "SVN (2015 snapshot)" +core_version: "0.9.11" +version_basis: + kind: file + path: "desmume/src/version.c" + pattern: '#define\s+DESMUME_VERSION_STRING\s+" "\s+"([^"]+)"' display_name: "Nintendo - DS (DeSmuME 2015)" cores: [desmume2015, desmume_2015] systems: [nintendo-ds] diff --git a/emulators/devilutionx.yml b/emulators/devilutionx.yml index 038e0c468..0c7dfcb13 100644 --- a/emulators/devilutionx.yml +++ b/emulators/devilutionx.yml @@ -6,6 +6,10 @@ upstream: ~ profiled_date: "2026-10-04" source_commit: "9d4871587e1a8d9606f97a43d85e939b82f77900" core_version: "1.6.0-dev" +version_basis: + kind: file + path: "VERSION" + pattern: '^(\S+)$' display_name: "Diablo (DevilutionX)" cores: [devilutionx] systems: [diablo] diff --git a/emulators/dgen.yml b/emulators/dgen.yml index d48858408..2fd22f363 100644 --- a/emulators/dgen.yml +++ b/emulators/dgen.yml @@ -5,6 +5,9 @@ source: "https://sourceforge.net/p/dgen/dgen" profiled_date: "2026-10-20" source_commit: "1c196e63d3e35704a97a2cef60def9df3c9fd1ce" core_version: "1.33" +version_basis: + kind: unverified + why: host_unsupported display_name: "Sega - Mega Drive - Genesis (DGen/SDL)" mode: standalone cores: diff --git a/emulators/dhewm3.yml b/emulators/dhewm3.yml index 38a002c37..35b19d0db 100644 --- a/emulators/dhewm3.yml +++ b/emulators/dhewm3.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/dhewm/dhewm3" profiled_date: "2026-10-04" source_commit: "455b88e8dff2be822f08eb498f51b383e851fa38" core_version: "1.5.5" +version_basis: + kind: tag + tag: "1.5.5" + distance: 0 display_name: "dhewm3" cores: [] systems: [doom3] diff --git a/emulators/dice.yml b/emulators/dice.yml index 836ba3d7d..d4867cc12 100644 --- a/emulators/dice.yml +++ b/emulators/dice.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/dice/" profiled_date: "2026-03-23" source_commit: "4b4596b8dd2252b9d08bd6aaa02afda4be834db3" core_version: "v0.4.3" +version_basis: + kind: tag + tag: "v0.4.3" + distance: 0 display_name: "Arcade (DICE)" cores: - dice diff --git a/emulators/dingooemu.yml b/emulators/dingooemu.yml index edfc41f63..b7a9483b3 100644 --- a/emulators/dingooemu.yml +++ b/emulators/dingooemu.yml @@ -5,7 +5,11 @@ source: "https://github.com/AloysHF/DingooEmu" upstream: "https://github.com/AloysHF/DingooEmu" profiled_date: "2026-09-17" source_commit: "f57c9339e6021cd37c4bd694c14b0813a9b5ee72" -core_version: "0.3.0" +core_version: "v0.3.0" +version_basis: + kind: tag + tag: "v0.3.0" + distance: 0 display_name: "Dingoo - A320 / Gemei A330 (DingooEmu)" cores: - dingooemu diff --git a/emulators/dinothawr.yml b/emulators/dinothawr.yml index 46ae02f63..19fbb5279 100644 --- a/emulators/dinothawr.yml +++ b/emulators/dinothawr.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/libretro/Dinothawr" profiled_date: "2026-03-23" source_commit: "62d3e1ecf85f0feea01cad6809a80303a87e8a28" core_version: "v1.0" +version_basis: + kind: file + path: "libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Dinothawr" cores: [dinothawr] systems: [dinothawr] diff --git a/emulators/directxbox.yml b/emulators/directxbox.yml index 3cbe83792..2081e3213 100644 --- a/emulators/directxbox.yml +++ b/emulators/directxbox.yml @@ -5,6 +5,10 @@ source: "https://github.com/libretro/libretro-directxbox" profiled_date: "2026-03-23" source_commit: "8b6b806675065efa7addb833e56fff7c05193bb1" core_version: "alpha" +version_basis: + kind: file + path: "src/libretro/libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Microsoft - Xbox (DirectXbox)" cores: - directxbox diff --git a/emulators/dirksimple.yml b/emulators/dirksimple.yml index 361a065b1..66e4e3ec1 100644 --- a/emulators/dirksimple.yml +++ b/emulators/dirksimple.yml @@ -5,7 +5,11 @@ source: "https://github.com/icculus/DirkSimple" upstream: "https://github.com/icculus/DirkSimple" profiled_date: "2026-03-23" source_commit: "d5d75f97af34690010166a786ee41e15dd142c15" -core_version: "0.2" +core_version: "0.3" +version_basis: + kind: file + path: "dirksimple_libretro.c" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "Laserdisc arcade game (DirkSimple)" cores: [dirksimple] systems: diff --git a/emulators/dolphin-mmjr.yml b/emulators/dolphin-mmjr.yml index ce9095ae6..932b85f63 100644 --- a/emulators/dolphin-mmjr.yml +++ b/emulators/dolphin-mmjr.yml @@ -7,6 +7,10 @@ profiled_date: "2026-08-11" source_commit: "1b095b64857c2eabb49a42cc56ffd9d7881bc263" upstream_commit: "0f4c971326ae9389b3ad55b0fefacb708d148f4d" core_version: "11460 - bankaimaster999" +version_basis: + kind: file + path: "Source/Android/app/build.gradle" + pattern: 'return versionNumber \+ "([^"]+)"' display_name: "Nintendo - GameCube / Wii (Dolphin MMJR)" cores: - dolphin-mmjr diff --git a/emulators/dolphin-mmjr2.yml b/emulators/dolphin-mmjr2.yml index 83eecabed..16f2e81ea 100644 --- a/emulators/dolphin-mmjr2.yml +++ b/emulators/dolphin-mmjr2.yml @@ -7,6 +7,10 @@ profiled_date: "2026-08-11" source_commit: "4d0fdb8eea616320e967408cf5547c72a95196f3" upstream_commit: "3eb30c7620b4475b2e0404228ba0d2b238a132f1" core_version: "2.0-18025" +version_basis: + kind: file + path: "Source/Android/app/build.gradle" + pattern: 'def getVersion\(\)\s*\{\s*return \u0027([^\u0027]+)\u0027' display_name: "Nintendo - GameCube / Wii (Dolphin MMJR2)" cores: - dolphin-mmjr2 diff --git a/emulators/dolphin.yml b/emulators/dolphin.yml index 34dca89af..2f76cbd20 100644 --- a/emulators/dolphin.yml +++ b/emulators/dolphin.yml @@ -7,7 +7,11 @@ logo: "https://raw.githubusercontent.com/dolphin-emu/dolphin/master/Data/dolphin profiled_date: "2026-03-23" source_commit: "3aac3f052f733f8df2f1616843a4d2e14002ed11" upstream_commit: "0d93fc035539f25790deca638d06ee3b3b45ee64" -core_version: "Git" +core_version: "2609-437-g3aac3f0" +version_basis: + kind: tag + tag: "2609" + distance: 437 display_name: "Nintendo - GameCube / Wii (Dolphin)" library_name: "dolphin-emu" cores: diff --git a/emulators/dolphin_launcher.yml b/emulators/dolphin_launcher.yml index b94a9981b..17fade041 100644 --- a/emulators/dolphin_launcher.yml +++ b/emulators/dolphin_launcher.yml @@ -7,6 +7,10 @@ upstream: "https://github.com/dolphin-emu/dolphin" profiled_date: "2026-03-23" source_commit: "6d72f3093d33461821e4f7fde6d3308187e644b9" core_version: "1.2.0" +version_basis: + kind: tag + tag: "1.2.0" + distance: 0 display_name: "Nintendo - GameCube / Wii (Dolphin Launcher)" cores: - dolphin_launcher diff --git a/emulators/dosbox-pure-unleashed.yml b/emulators/dosbox-pure-unleashed.yml index 6d499708b..0a93e2e21 100644 --- a/emulators/dosbox-pure-unleashed.yml +++ b/emulators/dosbox-pure-unleashed.yml @@ -8,6 +8,10 @@ upstream_commit: "7f6e8fb7385fa446d1444d671063268520bf9b54" logo: "https://raw.githubusercontent.com/schellingb/dosbox-pure-unleashed/main/images/logo.png" profiled_date: "2026-08-08" core_version: "1.0-preview6" +version_basis: + kind: tag + tag: "1.0-preview6" + distance: 0 display_name: "DOS (DOSBox Pure Unleashed)" cores: - dosbox-pure-unleashed diff --git a/emulators/dosbox-sdl2.yml b/emulators/dosbox-sdl2.yml index 205a970e2..c2bba4ae0 100644 --- a/emulators/dosbox-sdl2.yml +++ b/emulators/dosbox-sdl2.yml @@ -5,7 +5,11 @@ source: "https://github.com/duganchen/dosbox" upstream: "https://sourceforge.net/projects/dosbox/" profiled_date: "2026-10-20" source_commit: "e6b88ad03202d1f74e329f54f213d3b070bd6202" -core_version: "0.74-2" +core_version: "r3911-xbrz-428-ge6b88ad" +version_basis: + kind: tag + tag: "r3911-xbrz" + distance: 428 display_name: "DOS (DOSBox SDL2)" cores: [dosbox-sdl2, "DOSBOXSDL2"] systems: [dos] diff --git a/emulators/dosbox-staging.yml b/emulators/dosbox-staging.yml index 1739d9975..689a536d4 100644 --- a/emulators/dosbox-staging.yml +++ b/emulators/dosbox-staging.yml @@ -6,6 +6,11 @@ upstream: "https://github.com/dosbox-staging/dosbox-staging" source_commit: "fa1856c057902be3e08856675d6cc1e7ffe43db6" profiled_date: "2026-10-26" core_version: "0.84.0-alpha" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'project\(dosbox-staging[^)]*?VERSION\s+([0-9.]+)[^)]*\)\s*\n\s*set\(DOSBOX_VERSION \$\{PROJECT_VERSION\}(\S*)\)' + format: "{1}{2}" display_name: "DOS (DOSBox Staging)" cores: - dosbox-staging diff --git a/emulators/dosbox-x.yml b/emulators/dosbox-x.yml index 62997ce6e..74dae2715 100644 --- a/emulators/dosbox-x.yml +++ b/emulators/dosbox-x.yml @@ -5,7 +5,11 @@ source: "https://github.com/joncampbell123/dosbox-x" upstream: "https://github.com/joncampbell123/dosbox-x" source_commit: "997f616e0886a835fc3660f2b935688f17f20d42" profiled_date: "2026-09-17" -core_version: "2026.08.31" +core_version: "2026.10.01" +version_basis: + kind: file + path: "configure.ac" + pattern: 'AC_INIT\(dosbox-x,\s*([0-9.]+)' display_name: "DOS (DOSBox-X)" cores: - dosbox-x diff --git a/emulators/dosbox.yml b/emulators/dosbox.yml index 4cd5e6471..9ea8ff7d6 100644 --- a/emulators/dosbox.yml +++ b/emulators/dosbox.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/dosbox-libretro" upstream: "https://sourceforge.net/projects/dosbox/" profiled_date: "2026-10-04" source_commit: "a563bb5e9753f207d74e9d8c417d793b784fa4be" -core_version: "SVN" +core_version: "r4494" +version_basis: + kind: file + path: "libretro/svn" + pattern: '^(r\d+)' display_name: "DOS (DOSBox)" cores: [dosbox] systems: [dos] diff --git a/emulators/dosbox_core.yml b/emulators/dosbox_core.yml index c0627e052..e9e3b0e08 100644 --- a/emulators/dosbox_core.yml +++ b/emulators/dosbox_core.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/dosbox-core" upstream: "https://sourceforge.net/projects/dosbox/" profiled_date: "2026-03-23" source_commit: "d38fcb5013e4dca8d119a9786279cf41465757f2" -core_version: "SVN" +core_version: "r4494" +version_basis: + kind: file + path: "libretro/svn" + pattern: '^(r\d+)' display_name: "DOS (DOSBox-core)" cores: [dosbox_core] systems: [dos] diff --git a/emulators/dosbox_pure.yml b/emulators/dosbox_pure.yml index a91810ec0..63453181f 100644 --- a/emulators/dosbox_pure.yml +++ b/emulators/dosbox_pure.yml @@ -8,6 +8,11 @@ profiled_date: "2026-03-23" source_commit: "cdaea10ce8cac231bc341ca05d4c5e4e5fe0fbd5" upstream_commit: "cdaea10ce8cac231bc341ca05d4c5e4e5fe0fbd5" core_version: "1.0-preview7" +version_basis: + kind: tag + repo: upstream + tag: "1.0-preview7" + distance: 0 display_name: "DOS (DOSBox-Pure)" cores: [dosbox_pure] systems: [dos] diff --git a/emulators/dosbox_svn.yml b/emulators/dosbox_svn.yml index 1ff1b7a42..595f8df92 100644 --- a/emulators/dosbox_svn.yml +++ b/emulators/dosbox_svn.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/dosbox-svn" upstream: "https://sourceforge.net/projects/dosbox/" profiled_date: "2026-03-23" source_commit: "46a3164fc0f1e808ae56143d81698b00fb6b4781" -core_version: "SVN" +core_version: "SVN-libretro" +version_basis: + kind: file + path: "include/config.h" + pattern: '#define\s+VERSION\s+"([^"]+)"' display_name: "DOS (DOSBox-SVN)" cores: [dosbox_svn] systems: [dos] diff --git a/emulators/dosbox_svn_ce.yml b/emulators/dosbox_svn_ce.yml index 23aa3be53..ba4f37e14 100644 --- a/emulators/dosbox_svn_ce.yml +++ b/emulators/dosbox_svn_ce.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/dosbox-svn" upstream: "https://sourceforge.net/projects/dosbox/" profiled_date: "2026-03-23" source_commit: "46a3164fc0f1e808ae56143d81698b00fb6b4781" -core_version: "SVN CE" +core_version: "SVN-libretro" +version_basis: + kind: file + path: "include/config.h" + pattern: '#define\s+VERSION\s+"([^"]+)"' display_name: "DOS (DOSBox-SVN CE)" cores: [dosbox_svn_ce] systems: [dos] diff --git a/emulators/doublecherrygb.yml b/emulators/doublecherrygb.yml index 1c8e1a853..c433ac8b9 100644 --- a/emulators/doublecherrygb.yml +++ b/emulators/doublecherrygb.yml @@ -5,7 +5,11 @@ source: "https://github.com/TimOelrichs/doublecherryGB-libretro" upstream: "https://github.com/libertyernie/tgbdual" profiled_date: "2026-03-22" source_commit: "2e7a8bd5442ad7b2cb98ea07dbb5000ac95193e9" -core_version: "v0.18.1" +core_version: "0.18.1" +version_basis: + kind: tag + tag: "0.18.1" + distance: 0 display_name: "Nintendo - Game Boy / Color (DoubleCherryGB)" cores: - DoubleCherryGB diff --git a/emulators/doukutsu_rs.yml b/emulators/doukutsu_rs.yml index c7a4cf5be..149a5172c 100644 --- a/emulators/doukutsu_rs.yml +++ b/emulators/doukutsu_rs.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/doukutsu-rs/doukutsu-rs" profiled_date: "2026-03-23" source_commit: "51e64c2e9615bcd476034c69b58927877fe73494" upstream_commit: "d05995b2ce88e583491fcecfbd5883735d3527ea" -core_version: "1.2.0 - 0.101.0" +core_version: "0.102.0" +version_basis: + kind: file + path: "Cargo.toml" + pattern: '\[package\][^\[]*?^version\s*=\s*"([^"]+)"' display_name: "Cave Story (drs)" cores: - doukutsu_rs diff --git a/emulators/drastic.yml b/emulators/drastic.yml index ad8d041fa..a71c488af 100644 --- a/emulators/drastic.yml +++ b/emulators/drastic.yml @@ -9,6 +9,10 @@ version_source: author: "Exophase (Gilead Kutnick)" profiled_date: "2026-08-11" core_version: "r2.6.0.4a" +version_basis: + kind: package + url: "https://archive.org/details/dra-stic-ds-emulator-r-2.6.0.4a" + artifact: "com.dsemu.drastic APK versionName (build 109)" display_name: "Nintendo - DS (DraStic)" cores: - drastic diff --git a/emulators/dreamm.yml b/emulators/dreamm.yml index e25f6b715..e22c8ac61 100644 --- a/emulators/dreamm.yml +++ b/emulators/dreamm.yml @@ -8,6 +8,11 @@ version_source: pattern: 'Latest Release: ([0-9.]+)' profiled_date: "2026-08-08" core_version: "4.0" +version_basis: + kind: package + url: "https://dreamm.aarongiles.com/" + pattern: 'dreamm-(\d+(?:\.\d+)+)-win32-x64\.zip' + artifact: "dreamm-4.0-win32-x64.zip" display_name: "LucasArts (DREAMM)" cores: - dreamm diff --git a/emulators/droidarcadia.yml b/emulators/droidarcadia.yml index da6ad79cc..d2e2202bd 100644 --- a/emulators/droidarcadia.yml +++ b/emulators/droidarcadia.yml @@ -9,6 +9,10 @@ version_source: author: "James Jacobs (Amigan Software)" profiled_date: "2026-10-24" core_version: "4.75" +version_basis: + kind: package + url: "https://amigan.1emu.net/releases/" + artifact: "DroidArcadia-src.rar, release 4.75 on the author's releases page" display_name: "Emerson Arcadia 2001 / Interton VC 4000 (DroidArcadia)" cores: - droidarcadia diff --git a/emulators/dsda-doom.yml b/emulators/dsda-doom.yml index 2b864d709..488cfd6f2 100644 --- a/emulators/dsda-doom.yml +++ b/emulators/dsda-doom.yml @@ -4,7 +4,11 @@ core_classification: game_engine source: "https://github.com/dsda-org/dsda-doom" profiled_date: "2026-10-20" source_commit: "e443ff7a3e6090a1ff92ad7a426916c4fd35ecc5" -core_version: "0.29.4" +core_version: "v0.29.4" +version_basis: + kind: tag + tag: "v0.29.4" + distance: 0 display_name: "Doom (dsda-doom)" cores: [dsda-doom] systems: [doom, heretic, hexen, chex] diff --git a/emulators/dsmile.yml b/emulators/dsmile.yml index ef0d55304..0ee13f513 100644 --- a/emulators/dsmile.yml +++ b/emulators/dsmile.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/derik-dot-digital/D.Smile" profiled_date: "2026-08-11" source_commit: "d4bbc3be27537def21513991647f14ea9a9c2d15" core_version: "0.4.4" +version_basis: + kind: file + path: "app/build.gradle.kts" + pattern: 'versionName\s+=\s+"([^"]+)' display_name: "VTech - V.Smile (D.Smile)" cores: - dsmile diff --git a/emulators/dsperate.yml b/emulators/dsperate.yml index 3074eef96..9058a2dfa 100644 --- a/emulators/dsperate.yml +++ b/emulators/dsperate.yml @@ -5,7 +5,11 @@ source: "https://github.com/beebono/DSperate" profiled_date: "2026-10-17" source_commit: "81b73832c2e68e2b10cb5850f0a6d393ffc6fbb7" pin_frozen: "ROCKNIX 20261001 ships the v2.0.1 release binaries, built by CI from the v2.0.1 tag at this commit." -core_version: "2.0.1" +core_version: "v2.0.1" +version_basis: + kind: tag + tag: "v2.0.1" + distance: 0 display_name: "Nintendo - DS / DSi (DSperate)" cores: - "dsperate" diff --git a/emulators/duckstation-legacy.yml b/emulators/duckstation-legacy.yml index c892d744e..35e5bf244 100644 --- a/emulators/duckstation-legacy.yml +++ b/emulators/duckstation-legacy.yml @@ -5,7 +5,11 @@ source: "https://github.com/stenzek/duckstation" profiled_date: "2026-10-22" source_commit: "56ac3d6c324ec4520dac433b071ecab6227fb459" pin_frozen: "Batocera builds this revision of 4 August 2023 as duckstation-legacy, its package marked not to be bumped, and KNULLI ships the same package." -core_version: "0.1" +core_version: "0.1-5612-g56ac3d6" +version_basis: + kind: tag + tag: "0.1" + distance: 5612 display_name: "Sony - PlayStation (DuckStation legacy)" cores: - "duckstation-legacy" diff --git a/emulators/duckstation.yml b/emulators/duckstation.yml index 2207aeafa..4ca42ece5 100644 --- a/emulators/duckstation.yml +++ b/emulators/duckstation.yml @@ -6,7 +6,12 @@ upstream: "https://github.com/stenzek/duckstation" logo: "https://raw.githubusercontent.com/stenzek/duckstation/master/data/resources/images/duck.png" profiled_date: "2026-03-23" source_commit: "526b4a128827ecaef037134095cd95f431b52d06" -core_version: "v0.1-12070" +core_version: "v0.1-12083-406-g526b4a1" +version_basis: + kind: tag + match: "v*" + tag: "v0.1-12083" + distance: 406 display_name: "Sony - PlayStation (DuckStation)" cores: [duckstation, "Duckstation", "duckstation-sa"] found_by: content diff --git a/emulators/dusklight.yml b/emulators/dusklight.yml index aea0a641f..a4e33fbcd 100644 --- a/emulators/dusklight.yml +++ b/emulators/dusklight.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/TwilitRealm/dusklight" source_commit: "40457c6adb381928e4b5fef6ed459ed291edd5e2" profiled_date: "2026-10-20" core_version: "v2.0.3" +version_basis: + kind: tag + tag: "v2.0.3" + distance: 0 display_name: "The Legend of Zelda: Twilight Princess (Dusklight)" cores: [dusklight] systems: [dusklight] diff --git a/emulators/dxx-rebirth.yml b/emulators/dxx-rebirth.yml index d4c6578aa..c61dec3d4 100644 --- a/emulators/dxx-rebirth.yml +++ b/emulators/dxx-rebirth.yml @@ -5,7 +5,12 @@ source: "https://github.com/dxx-rebirth/dxx-rebirth" upstream: ~ profiled_date: "2026-10-04" source_commit: "6943b924bea749543ef5729f31a28345e79716d2" -core_version: "git" +core_version: "0.61.0" +version_basis: + kind: file + path: "SConstruct" + pattern: 'VERSION_MAJOR: typing.Final\[int\] = (\d+)\s+VERSION_MINOR: typing.Final\[int\] = (\d+)\s+VERSION_MICRO: typing.Final\[int\] = (\d+)' + format: "{1}.{2}.{3}" display_name: "Descent 1 & 2 (DXX-Rebirth)" cores: [dxx-rebirth, d1x-rebirth, d2x-rebirth] systems: [descent, descent2] diff --git a/emulators/easyrpg.yml b/emulators/easyrpg.yml index 272369066..8ad40c578 100644 --- a/emulators/easyrpg.yml +++ b/emulators/easyrpg.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-23" source_commit: "a3fbb7c24fd5a39fd95388d09135256a6b19f1e4" upstream_commit: "096c004def987f3545198304b1b7a8352f284a50" core_version: "0.8.1.1" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'project\(EasyRPG_Player\s+VERSION\s+([0-9][\w.+-]*)' display_name: "RPG Maker 2000/2003 (EasyRPG)" cores: - easyrpg diff --git a/emulators/ecwolf.yml b/emulators/ecwolf.yml index 4b8c52d5d..682135aaa 100644 --- a/emulators/ecwolf.yml +++ b/emulators/ecwolf.yml @@ -6,6 +6,10 @@ upstream: "https://bitbucket.org/ecwolf/ecwolf" profiled_date: "2026-03-23" source_commit: "0cccd9a85d7ffa33fb695691a8a5db246606518c" core_version: "1.3.99999" +version_basis: + kind: file + path: "src/libretro/versiondefs.h" + pattern: '#define\s+DOTVERSIONSTR_NOREV\s+"([^"]+)"' display_name: "Wolfenstein 3D (ECWolf)" cores: [ecwolf, "ECWolf"] systems: [wolfenstein3d] diff --git a/emulators/eden-nightly.yml b/emulators/eden-nightly.yml index 4b77c6a7c..c3efcea5f 100644 --- a/emulators/eden-nightly.yml +++ b/emulators/eden-nightly.yml @@ -9,7 +9,11 @@ upstream: "https://git.eden-emu.dev/eden-emu/eden" source_mirror: "https://codeberg.org/eden-emu/eden" source_commit: "8648c27cbb4c17b176076b09ac245271829cbd9f" profiled_date: "2026-08-11" -core_version: "Git" +core_version: "v0.2.0-220-g8648c27" +version_basis: + kind: tag + tag: "v0.2.0" + distance: 220 display_name: "Eden Nightly (Nintendo Switch)" cores: ["eden-nightly"] systems: [nintendo-switch] diff --git a/emulators/eden.yml b/emulators/eden.yml index a524b4a1d..dda4dfba1 100644 --- a/emulators/eden.yml +++ b/emulators/eden.yml @@ -8,7 +8,11 @@ upstream: "https://git.eden-emu.dev/eden-emu/eden" source_mirror: "https://codeberg.org/eden-emu/eden" profiled_date: "2026-03-26" source_commit: "26a03d2473787abf3223b2d0e65b291eee00c1e1" -core_version: "0.1.1" +core_version: "v0.2.0-401-g26a03d2" +version_basis: + kind: tag + tag: "v0.2.0" + distance: 401 display_name: "Eden (Nintendo Switch)" cores: - eden diff --git a/emulators/eduke32.yml b/emulators/eduke32.yml index 60ad486b8..0c781d974 100644 --- a/emulators/eduke32.yml +++ b/emulators/eduke32.yml @@ -9,6 +9,11 @@ version_source: profiled_date: "2026-10-04" source_commit: "ec5824db81817866f70da326d3811bb0f52b3517" core_version: "20260807-10669-ec5824db8" +version_basis: + kind: package + url: "https://dukeworld.com/eduke32/synthesis/20260807-10669-ec5824db8/eduke32_src_20260807-10669-ec5824db8.tar.xz" + pattern: 'eduke32_src_(\d{8}-\d+-[0-9a-f]+)\.tar' + artifact: "eduke32_src_20260807-10669-ec5824db8.tar.xz" display_name: "EDuke32" cores: [eduke32] systems: [duke3d, nam, napalm, ww2gi] diff --git a/emulators/eightyone.yml b/emulators/eightyone.yml index dc198712b..bd2c20de4 100644 --- a/emulators/eightyone.yml +++ b/emulators/eightyone.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/charlierobson/EightyOne" profiled_date: "2026-10-17" source_commit: "39ea0cc26453f4026458cfff62f10223a6bb1724" core_version: "v1.2" +version_basis: + kind: tag + tag: "v1.2" + distance: 0 pin_frozen: "Recalbox, the only platform that ships this core, builds its tag v1.2 (Recalbox package/libretro-eightyone/libretro-eightyone.mk:8 at tag 10.1.1)." display_name: "Sinclair - ZX81 / ZX Spectrum (EightyOne, Recalbox)" cores: ["eightyone"] diff --git a/emulators/eka2l1.yml b/emulators/eka2l1.yml index a89262391..a9ec08407 100644 --- a/emulators/eka2l1.yml +++ b/emulators/eka2l1.yml @@ -11,7 +11,18 @@ source_commit: libretro: "e39ccac46e631be7470b4f420fb8eebed9c24eca" upstream_commit: libretro: "11f5b6cd141c0884a130ee45743f1f5e17bb1783" -core_version: "0.0.9" +core_version: + standalone: "0.0.9" + libretro: "0.0.9" +version_basis: + standalone: + kind: file + path: "src/emu/common/include/common/configure.h.in" + pattern: '#define\s+CURRENT_EKA2L1_VERSION_STRING\s+"([^"]+)"' + libretro: + kind: file + path: "src/emu/common/include/common/configure.h.in" + pattern: '#define\s+CURRENT_EKA2L1_VERSION_STRING\s+"([^"]+)"' display_name: "Nokia - Symbian / N-Gage (EKA2L1)" cores: - eka2l1 diff --git a/emulators/emucorev.yml b/emulators/emucorev.yml index bbabf6e30..2c43a987b 100644 --- a/emulators/emucorev.yml +++ b/emulators/emucorev.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/Vita3K/Vita3K" author: "Oleksandr (sashkinbro)" profiled_date: "2026-08-11" source_commit: "b71d8cf5397b1c6394e92eeb48427cd17e542971" -core_version: "0.1.8" +core_version: "v0.1.8" +version_basis: + kind: tag + tag: "v0.1.8" + distance: 0 display_name: "Sony - PlayStation Vita (EmuCoreV)" cores: - emucorev diff --git a/emulators/emucorex.yml b/emulators/emucorex.yml index 889c28981..f1e4aa854 100644 --- a/emulators/emucorex.yml +++ b/emulators/emucorex.yml @@ -9,7 +9,11 @@ source_commit: "bda532f311a77c828a4e6bdb4667d9e92dfdf62f" prose_written_at: "bda532f311a77c828a4e6bdb4667d9e92dfdf62f" upstream_commit: "c10a5c9ad951c517dc48b722b5b84eb9bf7fdb42" upstream_frozen: "The PCSX2 tree vendored in the app is this revision. Later PCSX2 commits are not in the port." -core_version: "0.5.1" +core_version: "v0.5.1" +version_basis: + kind: tag + tag: "v0.5.1" + distance: 0 display_name: "Sony - PlayStation 2 (EmuCoreX)" cores: - emucorex diff --git a/emulators/emucv.yml b/emulators/emucv.yml index 070ef664b..693a82b2e 100644 --- a/emulators/emucv.yml +++ b/emulators/emucv.yml @@ -6,6 +6,11 @@ profiled_date: "2026-09-17" pin_frozen: "the shipping core is this revision. HEAD removed the prototype from the tree on 2026-09-11 (a188c0f) and archived its last description files on 2026-09-12 (06a066a). The new skeleton has not yet been copied from libretro-emuscv1 (ROADMAP step 4.3). Recaling would repoint these refs at a tree that currently holds nothing but a roadmap." source_commit: "6a6e1b15c5d5afefbc3fefdd8b52f3f2c8c0a0eb" core_version: "0.00" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'set\(CORE_VERSION_MAJOR\s+"([^"]+)"\)[\s\S]*?set\(CORE_VERSION_MINOR\s+"([^"]+)"\)' + format: "{1}.{2}" display_name: "EPOCH - Cassette Vision (EmuCV)" cores: - emucv diff --git a/emulators/emuscv.yml b/emulators/emuscv.yml index 5c0aabbef..075345385 100644 --- a/emulators/emuscv.yml +++ b/emulators/emuscv.yml @@ -5,7 +5,12 @@ source: "https://github.com/wzcwzc/emuscv" upstream: "http://takeda-toshiya.my.coocan.jp/" profiled_date: "2026-03-23" source_commit: "6d6e4594d79862dd5c2ff7f725c109e4266f0b03" -core_version: "0.12" +core_version: "0.12.20220726135800" +version_basis: + kind: file + path: "Makefile.libretro" + pattern: '^EMUSCV_VERSION_MAJOR := (\d+)\s*\nEMUSCV_VERSION_MINOR := (\d+)\s*\n(?:#.*\n)*EMUSCV_VERSION_DATETIME := \u0027?(\d+)' + format: "{1}.{2}.{3}" display_name: "EPOCH/YENO Super Cassette Vision" cores: - emuscv diff --git a/emulators/emux_chip8.yml b/emulators/emux_chip8.yml index a918f8708..34027feb2 100644 --- a/emulators/emux_chip8.yml +++ b/emulators/emux_chip8.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/sronsse/emux" profiled_date: "2026-03-23" source_commit: "3e558cb15157fcb1944846a845547d369605c963" core_version: "0.1" +version_basis: + kind: file + path: "configure.ac" + pattern: 'AC_INIT\(\[emux\],\s+\[([0-9][\w.+-]*)' display_name: "CHIP-8 (Emux CHIP-8)" cores: - emux_chip8 diff --git a/emulators/emux_gb.yml b/emulators/emux_gb.yml index 2822226cc..660d22424 100644 --- a/emulators/emux_gb.yml +++ b/emulators/emux_gb.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/sronsse/emux" profiled_date: "2026-03-23" source_commit: "3e558cb15157fcb1944846a845547d369605c963" core_version: "0.1" +version_basis: + kind: file + path: "configure.ac" + pattern: 'AC_INIT\(\[emux\],\s+\[([0-9][\w.+-]*)' display_name: "Nintendo - Game Boy / Color (Emux GB)" cores: - emux_gb diff --git a/emulators/emux_nes.yml b/emulators/emux_nes.yml index b97df551c..15a0cbf25 100644 --- a/emulators/emux_nes.yml +++ b/emulators/emux_nes.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/sronsse/emux" profiled_date: "2026-03-23" source_commit: "3e558cb15157fcb1944846a845547d369605c963" core_version: "0.1" +version_basis: + kind: file + path: "configure.ac" + pattern: 'AC_INIT\(\[emux\],\s+\[([0-9][\w.+-]*)' display_name: "Nintendo - NES / Famicom (Emux NES)" cores: - emux_nes diff --git a/emulators/emux_sms.yml b/emulators/emux_sms.yml index 507c04e53..45bc7789b 100644 --- a/emulators/emux_sms.yml +++ b/emulators/emux_sms.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/sronsse/emux" profiled_date: "2026-03-23" source_commit: "3e558cb15157fcb1944846a845547d369605c963" core_version: "0.1" +version_basis: + kind: file + path: "configure.ac" + pattern: 'AC_INIT\(\[emux\],\s+\[([0-9][\w.+-]*)' display_name: "Sega - Master System (Emux SMS)" cores: - emux_sms diff --git a/emulators/ep128emu.yml b/emulators/ep128emu.yml index 6007549e3..0f43da1c4 100644 --- a/emulators/ep128emu.yml +++ b/emulators/ep128emu.yml @@ -3,6 +3,9 @@ type: alias alias_of: "ep128emu_core" profiled_date: "2026-03-30" core_version: "v1.2.13" +version_basis: + kind: alias + of: "ep128emu_core" display_name: "Enterprise - 64/128 (ep128emu)" cores: - ep128emu diff --git a/emulators/ep128emu_core.yml b/emulators/ep128emu_core.yml index 13a044260..23e738ad4 100644 --- a/emulators/ep128emu_core.yml +++ b/emulators/ep128emu_core.yml @@ -7,6 +7,10 @@ upstream: https://github.com/istvan-v/ep128emu profiled_date: "2026-03-30" source_commit: "6af5d03de220e6effcd0ffcd99e0fb8e8c77cc9e" core_version: "v1.2.13" +version_basis: + kind: file + path: "core/main.cpp" + pattern: 'library_version\s*=\s*"([^"]+)"' cores: - ep128emu_core diff --git a/emulators/epsxe.yml b/emulators/epsxe.yml index 2108dd6a6..44ee5dd1d 100644 --- a/emulators/epsxe.yml +++ b/emulators/epsxe.yml @@ -9,6 +9,12 @@ version_source: author: "calb, _Demo_, Galtor (ePSXe Software S.L.)" profiled_date: "2026-08-11" core_version: "2.0.18" +version_basis: + kind: package + url: "https://www.epsxe.com/files/ePSXe2018.zip" + pattern: 'ePSXe(\d)(\d)(\d+)\.zip' + format: "{1}.{2}.{3}" + artifact: "ePSXe2018.zip" display_name: "Sony - PlayStation (ePSXe)" cores: - epsxe diff --git a/emulators/eternal.yml b/emulators/eternal.yml index 774d61ee6..d8de22e9c 100644 --- a/emulators/eternal.yml +++ b/emulators/eternal.yml @@ -7,6 +7,10 @@ source_commit: "13adf143aea822ebc1ee23722a80e93a7979e4c9" upstream_commit: "23d4d6c7c9f930fa72568ce795c9147af09d56ee" profiled_date: "2026-09-17" core_version: "0.0" +version_basis: + kind: file + path: "libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Eternal Computer" cores: - eternal diff --git a/emulators/etlegacy.yml b/emulators/etlegacy.yml index 5dd6473a3..1cb547b8e 100644 --- a/emulators/etlegacy.yml +++ b/emulators/etlegacy.yml @@ -5,7 +5,12 @@ source: "https://github.com/etlegacy/etlegacy" upstream: "https://github.com/etlegacy/etlegacy" profiled_date: "2026-10-04" source_commit: "add16a92f4b10c2955136e3ab7868bfc9bff8fad" -core_version: "2.86.2+git" +core_version: "2.86.2" +version_basis: + kind: file + path: "VERSION.txt" + pattern: '^VERSION_MAJOR (\d+)\s*\nVERSION_MINOR (\d+)\s*\nVERSION_PATCH (\d+)' + format: "{1}.{2}.{3}" display_name: "ET: Legacy" cores: [etlegacy] systems: [enemyterritory] diff --git a/emulators/exel-hence.yml b/emulators/exel-hence.yml index dad472d80..84da03588 100644 --- a/emulators/exel-hence.yml +++ b/emulators/exel-hence.yml @@ -6,6 +6,10 @@ upstream: "https://gitlab.com/recalbox/packages/recalbox-cores/libretro-exel-hen profiled_date: "2026-10-17" source_commit: "213328332cbfd8121e018493443e223a7a780961" core_version: "v0.9" +version_basis: + kind: tag + tag: "v0.9" + distance: 0 pin_frozen: "Recalbox, the only platform that ships this core, builds its tag v0.9 (Recalbox package/libretro-exel-hence/libretro-exel-hence.mk:9 at tag 10.1.1)." display_name: "Exelvision - EXL 100 (Exel-Hence)" cores: diff --git a/emulators/fake08.yml b/emulators/fake08.yml index c70489851..a6a62586a 100644 --- a/emulators/fake08.yml +++ b/emulators/fake08.yml @@ -6,6 +6,11 @@ upstream: "https://github.com/jtothebell/fake-08" profiled_date: "2026-03-23" source_commit: "814991a2571ad3970e386cef48f3b148aa1c27b9" core_version: "v0.0.2.20" +version_basis: + kind: file + path: "Makefile" + pattern: '^export V_MAJOR\s*=\s*(\d+)\s*\nexport V_MINOR\s*=\s*(\d+)\s*\nexport V_PATCH\s*=\s*(\d+)\s*\nexport V_BUILD\s*=\s*(\d+)' + format: "v{1}.{2}.{3}.{4}" display_name: "PICO-8 (FAKE-08)" cores: - fake08 diff --git a/emulators/fallout1-ce.yml b/emulators/fallout1-ce.yml index d1601e0ad..4878f708a 100644 --- a/emulators/fallout1-ce.yml +++ b/emulators/fallout1-ce.yml @@ -5,7 +5,11 @@ source: "https://github.com/alexbatalov/fallout1-ce" upstream: ~ profiled_date: "2026-10-04" source_commit: "0609bcfd0ec40ff0571d0f57fab2821eb461dc8b" -core_version: "1.1" +core_version: "v1.1.0-7-g0609bcf" +version_basis: + kind: tag + tag: "v1.1.0" + distance: 7 display_name: "Fallout (Community Edition)" cores: [fallout1-ce, "fallout-ce"] systems: [fallout] diff --git a/emulators/fallout2-ce.yml b/emulators/fallout2-ce.yml index 9af483cba..65f409c2d 100644 --- a/emulators/fallout2-ce.yml +++ b/emulators/fallout2-ce.yml @@ -5,7 +5,11 @@ source: "https://github.com/alexbatalov/fallout2-ce" upstream: ~ profiled_date: "2026-10-04" source_commit: "e97087b9582f37075db347a89898887320753f8b" -core_version: "v1.3.0" +core_version: "1.3.0" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'MACOSX_BUNDLE_SHORT_VERSION_STRING\s+"([^"]+)"' display_name: "Fallout 2 (Community Edition)" cores: [fallout2-ce] systems: [fallout2] diff --git a/emulators/fba2x.yml b/emulators/fba2x.yml index 4f9f3e2c8..49894d147 100644 --- a/emulators/fba2x.yml +++ b/emulators/fba2x.yml @@ -5,7 +5,12 @@ source: "https://github.com/recalbox/pifba" upstream: "https://github.com/finalburn/fbalpha-fork" profiled_date: "2026-10-04" source_commit: "419faa7c3967560f6fa149f2f78b5aedca5b123a" -core_version: "0.2.97.x" +core_version: "0.2.96.71" +version_basis: + kind: file + path: "burn/version.h" + pattern: '#define\s+VER_MAJOR\s+(\d+)\s*\n#define\s+VER_MINOR\s+(\d+)\s*\n#define\s+VER_BETA\s+(\d+)\s*\n#define\s+VER_ALPHA\s+(\d+)' + format: "{1}.{2}.{3}.{4}" display_name: "Arcade (piFBA / fba2x)" cores: [fba2x, pifba] systems: diff --git a/emulators/fbalpha2012.yml b/emulators/fbalpha2012.yml index 73c886a81..4d54627cb 100644 --- a/emulators/fbalpha2012.yml +++ b/emulators/fbalpha2012.yml @@ -5,7 +5,12 @@ source: "https://github.com/libretro/fbalpha2012" upstream: "https://www.fbalpha.com" profiled_date: "2026-03-23" source_commit: "0ce31536bef3162fe7e69ff5f555334ec4913cef" -core_version: "v0.2.97.29" +core_version: "v0.2.97.30" +version_basis: + kind: file + path: "svn-current/trunk/src/burn/version.h" + pattern: '#define\s+VER_MAJOR\s+(\d+)\s*\n#define\s+VER_MINOR\s+(\d+)\s*\n#define\s+VER_BETA\s+(\d+)\s*\n#define\s+VER_ALPHA\s+(\d+)' + format: "v{1}.{2}.{3}.{4}" display_name: "Arcade (FB Alpha 2012)" library_name: "FB Alpha 2012" cores: diff --git a/emulators/fbalpha2012_cps1.yml b/emulators/fbalpha2012_cps1.yml index 7931815e0..3e85ca306 100644 --- a/emulators/fbalpha2012_cps1.yml +++ b/emulators/fbalpha2012_cps1.yml @@ -6,6 +6,10 @@ upstream: "https://www.fbalpha.com" profiled_date: "2026-03-23" source_commit: "5542c1848ef81e92db311193b01dc349bc29d7cc" core_version: "v0.2.97.28" +version_basis: + kind: file + path: "src/burner/libretro/libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Arcade (FB Alpha 2012 CPS-1)" cores: - fbalpha2012_cps1 diff --git a/emulators/fbalpha2012_cps2.yml b/emulators/fbalpha2012_cps2.yml index 5387c8783..5bee02d1f 100644 --- a/emulators/fbalpha2012_cps2.yml +++ b/emulators/fbalpha2012_cps2.yml @@ -6,6 +6,10 @@ upstream: "https://www.fbalpha.com" profiled_date: "2026-03-23" source_commit: "e3f3ae46f120228b74d41e2b2862f1fbf1d7eb5b" core_version: "v0.2.97.28" +version_basis: + kind: file + path: "src/burner/libretro/libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Arcade (FB Alpha 2012 CPS-2)" cores: - fbalpha2012_cps2 diff --git a/emulators/fbalpha2012_cps3.yml b/emulators/fbalpha2012_cps3.yml index ed6d85bcd..cdb667f78 100644 --- a/emulators/fbalpha2012_cps3.yml +++ b/emulators/fbalpha2012_cps3.yml @@ -5,7 +5,12 @@ source: "https://github.com/libretro/fbalpha2012_cps3" upstream: "https://www.fbalpha.com" profiled_date: "2026-03-23" source_commit: "57f8015c2e0cdebcf42d3add2c314bb7448f9421" -core_version: "v0.2.97.29" +core_version: "v0.2.97.30" +version_basis: + kind: file + path: "svn-current/trunk/src/burn/version.h" + pattern: '#define\s+VER_MAJOR\s+(\d+)\s*\n#define\s+VER_MINOR\s+(\d+)\s*\n#define\s+VER_BETA\s+(\d+)\s*\n#define\s+VER_ALPHA\s+(\d+)' + format: "v{1}.{2}.{3}.{4}" display_name: "Arcade (FB Alpha 2012 CPS-3)" library_name: "FB Alpha 2012 CPS-3" cores: diff --git a/emulators/fbalpha2012_neogeo.yml b/emulators/fbalpha2012_neogeo.yml index e760d3c0d..47de1d852 100644 --- a/emulators/fbalpha2012_neogeo.yml +++ b/emulators/fbalpha2012_neogeo.yml @@ -6,6 +6,10 @@ upstream: "https://www.fbalpha.com" profiled_date: "2026-03-23" source_commit: "e092097037d494c50d17c5144a2758d68538061b" core_version: "v0.2.97.29" +version_basis: + kind: file + path: "src/burner/libretro/libretro.cpp" + pattern: '#define\s+FBA_VERSION\s+"([^"]+)' display_name: "Arcade (FB Alpha 2012 Neo Geo)" cores: - fbalpha2012_neogeo diff --git a/emulators/fbalpha2019.yml b/emulators/fbalpha2019.yml index 3d113071e..dc2100223 100644 --- a/emulators/fbalpha2019.yml +++ b/emulators/fbalpha2019.yml @@ -8,6 +8,10 @@ source_commit: "0581797db6fdffd826086b053ced4b6b29bb6678" upstream_commit: "416948158d88ba17f87813419ddc3c1209ef68c0" pin_frozen: "ROCKNIX 20261001 builds this revision as fbalpha2019. Later commits on libretro/fbalpha are not part of that build." core_version: "v0.2.97.44" +version_basis: + kind: file + path: "src/burner/libretro/libretro.cpp" + pattern: '#define\s+FBA_VERSION\s+"([^"]+)' display_name: "Arcade (FB Alpha 2019)" cores: - "fbalpha2019" diff --git a/emulators/fbneo.yml b/emulators/fbneo.yml index c07e291c5..4c397f359 100644 --- a/emulators/fbneo.yml +++ b/emulators/fbneo.yml @@ -7,7 +7,12 @@ logo: "https://raw.githubusercontent.com/finalburnneo/FBNeo/master/projectfiles/ profiled_date: "2026-10-23" source_commit: "32958a89abd645ed20387c8d31d21ede3bc48161" upstream_commit: "697e385c8285bfc528343b96d948ee3a4f9e24c5" -core_version: "v1.0.0.2" +core_version: "v1.0.0.03" +version_basis: + kind: file + path: "src/burn/version.h" + pattern: '#define\s+VER_MAJOR\s+(\d+)\s*\n#define\s+VER_MINOR\s+(\d+)\s*\n#define\s+VER_BETA\s+(\d+)\s*\n#define\s+VER_ALPHA\s+(\d+)' + format: "v{1}.{2}.{3}.{4:02d}" display_name: "Arcade (FinalBurn Neo)" cores: - fbneo diff --git a/emulators/fbneo_cps12.yml b/emulators/fbneo_cps12.yml index 8851a206b..4d2d50469 100644 --- a/emulators/fbneo_cps12.yml +++ b/emulators/fbneo_cps12.yml @@ -6,7 +6,12 @@ upstream: "https://github.com/finalburnneo/FBNeo" profiled_date: "2026-03-23" source_commit: "32958a89abd645ed20387c8d31d21ede3bc48161" upstream_commit: "697e385c8285bfc528343b96d948ee3a4f9e24c5" -core_version: "v1.0.0.2" +core_version: "v1.0.0.03" +version_basis: + kind: file + path: "src/burn/version.h" + pattern: '#define\s+VER_MAJOR\s+(\d+)\s*\n#define\s+VER_MINOR\s+(\d+)\s*\n#define\s+VER_BETA\s+(\d+)\s*\n#define\s+VER_ALPHA\s+(\d+)' + format: "v{1}.{2}.{3}.{4:02d}" display_name: "Arcade (FinalBurn Neo) (CPS-1 / CPS-2)" cores: - fbneo_cps12 diff --git a/emulators/fbneo_neogeo.yml b/emulators/fbneo_neogeo.yml index e74565e97..631c744e9 100644 --- a/emulators/fbneo_neogeo.yml +++ b/emulators/fbneo_neogeo.yml @@ -6,7 +6,12 @@ upstream: "https://github.com/finalburnneo/FBNeo" profiled_date: "2026-10-23" source_commit: "32958a89abd645ed20387c8d31d21ede3bc48161" upstream_commit: "697e385c8285bfc528343b96d948ee3a4f9e24c5" -core_version: "v1.0.0.2" +core_version: "v1.0.0.03" +version_basis: + kind: file + path: "src/burn/version.h" + pattern: '#define\s+VER_MAJOR\s+(\d+)\s*\n#define\s+VER_MINOR\s+(\d+)\s*\n#define\s+VER_BETA\s+(\d+)\s*\n#define\s+VER_ALPHA\s+(\d+)' + format: "v{1}.{2}.{3}.{4:02d}" display_name: "Arcade (FinalBurn Neo) (Neo-Geo)" cores: - fbneo_neogeo diff --git a/emulators/fbzx.yml b/emulators/fbzx.yml index cdd3d55e5..5151c7190 100644 --- a/emulators/fbzx.yml +++ b/emulators/fbzx.yml @@ -5,6 +5,10 @@ source: "https://github.com/rastersoft/fbzx" profiled_date: "2026-10-20" source_commit: "8d6b4cbe5fec121015e98cf545e9b3b811de2a71" core_version: "3.9.1" +version_basis: + kind: file + path: "src/menus.cpp" + pattern: 'print_string\("FBZX \(([0-9][^)"]*)\)"' display_name: "Sinclair - ZX Spectrum (FBZX)" mode: standalone cores: diff --git a/emulators/fceumm.yml b/emulators/fceumm.yml index b210da2ad..9a952e896 100644 --- a/emulators/fceumm.yml +++ b/emulators/fceumm.yml @@ -5,7 +5,9 @@ source: "https://github.com/libretro/libretro-fceumm" upstream: "https://sourceforge.net/projects/fceumm/" profiled_date: "2026-03-23" source_commit: "ac0d00a7fc01166f84c7bac01d1084ebfd2b865e" -core_version: "SVN" +core_version: null +version_basis: + kind: none display_name: "Nintendo - NES / Famicom (FCEUmm)" cores: - fceumm diff --git a/emulators/fceumm_mod.yml b/emulators/fceumm_mod.yml index 913e41b17..19d7a2065 100644 --- a/emulators/fceumm_mod.yml +++ b/emulators/fceumm_mod.yml @@ -5,7 +5,11 @@ source: "https://github.com/Tippek/libretro-fceumm-mod" upstream: "https://github.com/libretro/libretro-fceumm" profiled_date: "2026-10-22" source_commit: "f0ea52190427b136a51da4490e49087fe2ca2abb" -core_version: "SVN" +core_version: "0.9.45.1.0.0.D7a" +version_basis: + kind: file + path: "src/drivers/libretro/libretro.c" + pattern: 'library_version\s*=\s*"\(([^)"]+)\)"' display_name: "Nintendo - NES / Famicom (FCEUmm Mod)" cores: - "fceumm_mod" diff --git a/emulators/ffmpeg.yml b/emulators/ffmpeg.yml index f061e9a70..fea1d8979 100644 --- a/emulators/ffmpeg.yml +++ b/emulators/ffmpeg.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/FFmpeg" upstream: "https://www.ffmpeg.org/" profiled_date: "2026-03-23" source_commit: "4920879d2f09a78cdf855403c349457cee1c31da" -core_version: "Git" +core_version: "2.7.git" +version_basis: + kind: file + path: "RELEASE" + pattern: '^(\S+)' display_name: "FFmpeg" cores: - ffmpeg diff --git a/emulators/fheroes2.yml b/emulators/fheroes2.yml index 6cd29936c..75f787a71 100644 --- a/emulators/fheroes2.yml +++ b/emulators/fheroes2.yml @@ -6,6 +6,10 @@ profiled_date: "2026-10-22" source_commit: "35ca4c915be00098547d5050412a325dd55cfd7f" pin_frozen: "EmuELEC, the only platform that ships it, builds this revision (EmuELEC packages/sx05re/emuelec-ports/fheroes2/package.mk:5). Later commits are not part of that build." core_version: "1.0.11" +version_basis: + kind: file + path: "version.txt" + pattern: '^(\d[^\s]*)' display_name: "Heroes of Might and Magic II (fheroes2)" cores: - "fheroes2" diff --git a/emulators/fixgb.yml b/emulators/fixgb.yml index 597cc84ac..e166dd8b0 100644 --- a/emulators/fixgb.yml +++ b/emulators/fixgb.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/FIX94/fixGB" profiled_date: "2026-03-23" source_commit: "c7865087b8c8126b8bc60fddb75b20efad992458" core_version: "Alpha v0.8.2" +version_basis: + kind: file + path: "main.c" + pattern: 'VERSION_STRING\s*=\s*"fixGB ([^"]+)"' display_name: "Nintendo - Game Boy / Color (fixGB)" cores: - fixgb diff --git a/emulators/fixnes.yml b/emulators/fixnes.yml index d997942d9..b078437b6 100644 --- a/emulators/fixnes.yml +++ b/emulators/fixnes.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-23" source_commit: "72af6c6fd9d3b6c23d334ba7385b6a09225f2276" prose_written_at: "72af6c6fd9d3b6c23d334ba7385b6a09225f2276" core_version: "Alpha v1.3.1" +version_basis: + kind: file + path: "main.c" + pattern: 'VERSION_STRING\s*=\s*"fixNES ([^"]+)"' display_name: "Nintendo - NES / Famicom (fixNES)" cores: - fixnes diff --git a/emulators/flycast-dojo.yml b/emulators/flycast-dojo.yml index e3fe22e14..b782d6d89 100644 --- a/emulators/flycast-dojo.yml +++ b/emulators/flycast-dojo.yml @@ -9,7 +9,11 @@ upstream_commit: "f13d7ad2dcf141f59a999090dbc0f78be196e665" upstream_frozen: "The dojo branch carries flyinghead/flycast up to this commit, with the Dojo commits on top and no later merge." logo: "https://raw.githubusercontent.com/blueminder/flycast-dojo/master/shell/linux/flycast-dojo.png" profiled_date: "2026-10-27" -core_version: "dojo-7.9" +core_version: "dojo-7.9-1-gfa518ac" +version_basis: + kind: tag + tag: "dojo-7.9" + distance: 1 display_name: "Sega - Dreamcast/Naomi (Flycast Dojo)" cores: - flycast-dojo diff --git a/emulators/flycast.yml b/emulators/flycast.yml index 23925cfb2..0901a1fda 100644 --- a/emulators/flycast.yml +++ b/emulators/flycast.yml @@ -5,7 +5,11 @@ source: "https://github.com/flyinghead/flycast" logo: "https://raw.githubusercontent.com/flyinghead/flycast/master/shell/linux/flycast.png" profiled_date: "2026-10-21" source_commit: "e88b0ced2243de137bcccac0072f0c1dd00d41bd" -core_version: "Git" +core_version: "v2.7-90-ge88b0ce" +version_basis: + kind: tag + tag: "v2.7" + distance: 90 display_name: "Sega - Dreamcast/Naomi (Flycast)" cores: - flycast diff --git a/emulators/flycast2021.yml b/emulators/flycast2021.yml index 9ad942f82..7f6257b87 100644 --- a/emulators/flycast2021.yml +++ b/emulators/flycast2021.yml @@ -8,6 +8,10 @@ source_commit: "603814c9f73b773c455d9a497f389d2f93a257fd" upstream_commit: "4c293f306bc16a265c2d768af5d0cea138426054" pin_frozen: "ROCKNIX 20261001 builds this revision. No branch of metallic77/flycast holds it any more: master was put back on the libretro merge base 4c293f30, so HEAD is the code before the fork's own commits." core_version: "0.1" +version_basis: + kind: file + path: "core/libretro/libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Sega - Dreamcast/Naomi (Flycast 2021)" cores: - "flycast2021" diff --git a/emulators/flycast2021le.yml b/emulators/flycast2021le.yml index a2f9a8f80..e66242c0f 100644 --- a/emulators/flycast2021le.yml +++ b/emulators/flycast2021le.yml @@ -8,6 +8,10 @@ source_commit: "bf93aece5db7050667075a1107ab380856b44a23" upstream_commit: "4c293f306bc16a265c2d768af5d0cea138426054" pin_frozen: "AmberELEC, the only platform that ships it, builds this revision (AmberELEC packages/games/libretro/flycast2021le/package.mk:5). Later commits are not part of that build." core_version: "0.1" +version_basis: + kind: file + path: "core/libretro/libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Sega - Dreamcast/Naomi (Flycast 2021 LE)" cores: - "flycast2021le" diff --git a/emulators/flycast_gles2.yml b/emulators/flycast_gles2.yml index c704b227a..e21f1eca9 100644 --- a/emulators/flycast_gles2.yml +++ b/emulators/flycast_gles2.yml @@ -2,7 +2,10 @@ emulator: "Flycast GLES2" type: alias alias_of: "flycast" profiled_date: "2026-03-23" -core_version: "0.1" +core_version: "v2.7-90-ge88b0ce" +version_basis: + kind: alias + of: "flycast" display_name: "Sega - Dreamcast/Naomi (Flycast GLES2)" cores: - flycast_gles2 diff --git a/emulators/fmsx.yml b/emulators/fmsx.yml index 9cc2334a7..ea64e6953 100644 --- a/emulators/fmsx.yml +++ b/emulators/fmsx.yml @@ -6,6 +6,10 @@ upstream: "https://fms.komkon.org/fMSX/" profiled_date: "2026-03-23" source_commit: "4de11755ce4f196ac1c8a7bb20bb4eccbc87a7d4" core_version: "6.0" +version_basis: + kind: file + path: "libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Microsoft - MSX (fMSX)" cores: - fmsx diff --git a/emulators/fpse-ng.yml b/emulators/fpse-ng.yml index cfb92408a..acff63142 100644 --- a/emulators/fpse-ng.yml +++ b/emulators/fpse-ng.yml @@ -10,6 +10,10 @@ version_source: author: "Schtruck & LDchen" profiled_date: "2026-08-11" core_version: "1.13" +version_basis: + kind: package + url: "https://play.google.com/store/apps/details?id=com.emulator.fpse64" + artifact: "com.emulator.fpse64 APK versionName (versionCode 245)" display_name: "Sony - PlayStation (FPseNG)" cores: - "fpse-ng" diff --git a/emulators/fpse.yml b/emulators/fpse.yml index c476f9758..6ff069202 100644 --- a/emulators/fpse.yml +++ b/emulators/fpse.yml @@ -10,6 +10,10 @@ version_source: author: "Schtruck & LDchen (EMUSOFT)" profiled_date: "2026-08-11" core_version: "12.1" +version_basis: + kind: package + url: "https://play.google.com/store/apps/details?id=com.emulator.fpse" + artifact: "com.emulator.fpse APK versionName (versionCode 940)" display_name: "Sony - PlayStation (FPse)" cores: - fpse diff --git a/emulators/freechaf.yml b/emulators/freechaf.yml index ebb8383b7..a45926c2b 100644 --- a/emulators/freechaf.yml +++ b/emulators/freechaf.yml @@ -4,7 +4,11 @@ core_classification: pure_libretro source: "https://github.com/libretro/FreeChaF" profiled_date: "2026-03-23" source_commit: "76c7a84f1f7e80f3e6f2bba96fe100cb24e99124" -core_version: "GIT" +core_version: "1.0" +version_basis: + kind: file + path: "src/libretro.c" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "Fairchild - ChannelF (FreeChaF)" cores: - freechaf diff --git a/emulators/freeintv.yml b/emulators/freeintv.yml index 06a196437..e2448ea51 100644 --- a/emulators/freeintv.yml +++ b/emulators/freeintv.yml @@ -4,7 +4,11 @@ core_classification: pure_libretro source: "https://github.com/libretro/FreeIntv" profiled_date: "2026-03-23" source_commit: "ef3e0fe322bec62a7f916c0bb0834c08c348d0b4" -core_version: "2018.1.5" +core_version: "1.2" +version_basis: + kind: file + path: "src/libretro.c" + pattern: 'library_version\s*=\s*"([^" ]+)\s*"' display_name: "Mattel - Intellivision (FreeIntv)" cores: - freeintv diff --git a/emulators/freeintv_ts_overlay.yml b/emulators/freeintv_ts_overlay.yml index a84b982bc..8d35f02b6 100644 --- a/emulators/freeintv_ts_overlay.yml +++ b/emulators/freeintv_ts_overlay.yml @@ -6,6 +6,9 @@ source: "https://github.com/jcarr71/FreeIntvTSOverlay" upstream: "https://github.com/libretro/FreeIntv" profiled_date: "2026-03-22" core_version: "1.2" +version_basis: + kind: alias + of: "freeintv" display_name: "Mattel - Intellivision (FreeIntvTSOverlay)" cores: - freeintv diff --git a/emulators/freej2me.yml b/emulators/freej2me.yml index 9300db0b2..45a5bc303 100644 --- a/emulators/freej2me.yml +++ b/emulators/freej2me.yml @@ -5,7 +5,11 @@ source: "https://github.com/hex007/freej2me" upstream: "https://github.com/hex007/freej2me" profiled_date: "2026-03-23" source_commit: "eb4ac87e9a0b212ba701691eb67ee4892b2b1173" -core_version: "GIT" +core_version: "1.0.0" +version_basis: + kind: file + path: "META-INF/freej2me-build.version" + pattern: '^build\.version=(\S+)' display_name: "Mobile - J2ME (FreeJ2ME)" cores: - freej2me diff --git a/emulators/freej2me_plus.yml b/emulators/freej2me_plus.yml index 853535675..78f4ad875 100644 --- a/emulators/freej2me_plus.yml +++ b/emulators/freej2me_plus.yml @@ -7,6 +7,10 @@ profiled_date: "2026-10-04" source_commit: "3933e75ef927a95eab9f5e065f0b76dabf336069" upstream_commit: "8b9bc8a19baf26e3d92f88934a64a32f1cbc2795" core_version: "1.53" +version_basis: + kind: file + path: "src/libretro/freej2me_libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Mobile - J2ME (FreeJ2ME-Plus)" cores: - freej2me_plus diff --git a/emulators/frodo.yml b/emulators/frodo.yml index c96866083..6390fb90b 100644 --- a/emulators/frodo.yml +++ b/emulators/frodo.yml @@ -6,7 +6,11 @@ source: "https://github.com/libretro/frodo-libretro" upstream: "https://github.com/cebix/frodo4" profiled_date: "2026-03-23" source_commit: "891d20102a8894dd4fce73fb8bd2f623483fd05f" -core_version: "v4.2" +core_version: "V4.2" +version_basis: + kind: file + path: "Src/Version.h" + pattern: 'VERSION_STRING\[\]\s*=\s*"Frodo ([^"]+)"' display_name: "Commodore - C64 (Frodo)" systems: [commodore-c64] diff --git a/emulators/frotz.yml b/emulators/frotz.yml index f9b6cdf7e..5fb883341 100644 --- a/emulators/frotz.yml +++ b/emulators/frotz.yml @@ -5,7 +5,11 @@ source: "https://gitlab.com/DavidGriffith/frotz" upstream: "https://gitlab.com/DavidGriffith/frotz" profiled_date: "2026-10-17" source_commit: "042d7bcadc1e2a8090cf737c841d8b7fc14b6eff" -core_version: "2.55pre" +core_version: "2.56pre" +version_basis: + kind: file + path: "Makefile" + pattern: '^VERSION\s*=\s*(\S+)' display_name: "Infocom Z-Machine (SDL Frotz)" cores: - "frotz" diff --git a/emulators/fs-uae.yml b/emulators/fs-uae.yml index e201471bc..a27c83e40 100644 --- a/emulators/fs-uae.yml +++ b/emulators/fs-uae.yml @@ -4,7 +4,11 @@ core_classification: other source: "https://github.com/FrodeSolheim/fs-uae" profiled_date: "2026-10-20" source_commit: "596d803944f6498c305ac48d338f6252cbde7ecb" -core_version: "3.1.64" +core_version: "v3.1.64" +version_basis: + kind: tag + tag: "v3.1.64" + distance: 0 display_name: "Commodore - Amiga (FS-UAE 3.1)" cores: [fs-uae] systems: [commodore-amiga] diff --git a/emulators/fsuae.yml b/emulators/fsuae.yml index e059162ee..fc8a997d6 100644 --- a/emulators/fsuae.yml +++ b/emulators/fsuae.yml @@ -6,7 +6,12 @@ upstream: "https://github.com/FrodeSolheim/fs-uae" profiled_date: "2026-03-26" source_commit: "089bb69207fe8fa5eec0006d1d759fb6426f4027" upstream_commit: "f362278ccd4c60991caac3b4d240d4a3f751bea2" -core_version: "v5.0.7" +core_version: "5.0.7" +version_basis: + kind: file + repo: upstream + path: "configure.ac" + pattern: 'AC_INIT\(\[FS-UAE\],\s+\[([0-9][\w.+-]*)' display_name: "Commodore - Amiga (FS-UAE)" library_name: "" cores: diff --git a/emulators/fury.yml b/emulators/fury.yml index a844f8467..2894b01bc 100644 --- a/emulators/fury.yml +++ b/emulators/fury.yml @@ -9,6 +9,11 @@ version_source: profiled_date: "2026-10-04" source_commit: "ec5824db81817866f70da326d3811bb0f52b3517" core_version: "20260807-10669-ec5824db8" +version_basis: + kind: package + url: "https://dukeworld.com/eduke32/synthesis/latest/" + pattern: 'eduke32_src_(\d{8}-\d+-[0-9a-f]+)\.tar' + artifact: "eduke32_src_20260807-10669-ec5824db8.tar.xz" display_name: "Ion Fury" cores: [fury, ionfury] systems: [fury] diff --git a/emulators/fuse.yml b/emulators/fuse.yml index 2fea6a4ad..ec567ca64 100644 --- a/emulators/fuse.yml +++ b/emulators/fuse.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/fuse-emulator/" profiled_date: "2026-03-23" source_commit: "e997e2bc32c888348f862f69f2c53babfedf7791" core_version: "1.6.0" +version_basis: + kind: file + path: "fuse/configure.ac" + pattern: 'm4_define\(\[fuse_version\],\s*\[([^\]]+)\]\)' display_name: "Sinclair - ZX Spectrum (Fuse)" cores: - fuse diff --git a/emulators/future-pinball-fploader.yml b/emulators/future-pinball-fploader.yml index 7b036a34b..21b5a035f 100644 --- a/emulators/future-pinball-fploader.yml +++ b/emulators/future-pinball-fploader.yml @@ -6,6 +6,9 @@ upstream: "https://www.ravarcade.pl/" profiled_date: "2026-08-11" source_commit: "e13007994011ae57dd9d9f48674c1f774183914b" core_version: "1.5-408" +version_basis: + kind: unverified + why: no_artifact display_name: "Future Pinball (BAM)" cores: - future-pinball-fploader diff --git a/emulators/future-pinball.yml b/emulators/future-pinball.yml index 4f7bd5e8c..2e069ac97 100644 --- a/emulators/future-pinball.yml +++ b/emulators/future-pinball.yml @@ -8,6 +8,10 @@ version_source: pattern: 'The current version is ([0-9.]+)' profiled_date: "2026-08-11" core_version: "1.9.1.20101231" +version_basis: + kind: package + url: "https://futurepinball.com/home.html" + artifact: "Future Pinball release labelled 1.9.1.20101231 on futurepinball.com, Future Pinball.exe" display_name: "Future Pinball" cores: - fpinball diff --git a/emulators/galaksija.yml b/emulators/galaksija.yml index 18c81420b..746d1f918 100644 --- a/emulators/galaksija.yml +++ b/emulators/galaksija.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/galaxy-libretro" upstream: "https://github.com/nikp123/Galaksija-Emulator" profiled_date: "2026-03-23" source_commit: "185758296c17f59cba832511139381a197986474" -core_version: "v0.1" +core_version: "0.1" +version_basis: + kind: file + path: "src/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Elektronika Inženjering - Galaksija (Galaksija)" cores: - galaksija diff --git a/emulators/gam4980.yml b/emulators/gam4980.yml index a0ced2aa5..6fd297a35 100644 --- a/emulators/gam4980.yml +++ b/emulators/gam4980.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-23" source_commit: "eeaa531b55e7127ab4b5e0bdc5ceba686df59c6a" upstream_commit: "32c531d3e7159081afd8dee72e8266153821095d" core_version: "0.2" +version_basis: + kind: file + path: "src/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "GAM4980" cores: - gam4980 diff --git a/emulators/gambatte.yml b/emulators/gambatte.yml index e1ff8f20d..b509babbd 100644 --- a/emulators/gambatte.yml +++ b/emulators/gambatte.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/sinamas/gambatte" profiled_date: "2026-03-23" source_commit: "7809bb68ee96c3e6c74e9d9c4c8bb09aa7c6801d" core_version: "v0.5.0" +version_basis: + kind: file + path: "libgambatte/libretro/libretro.cpp" + pattern: 'library_version\s*=\s*"(v[0-9.]+)"\s*GIT_VERSION' display_name: "Nintendo - Game Boy / Color (Gambatte)" cores: - gambatte diff --git a/emulators/gametank.yml b/emulators/gametank.yml index 7479a7323..7ca371ec0 100644 --- a/emulators/gametank.yml +++ b/emulators/gametank.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/clydeshaffer/GameTankEmulator" profiled_date: "2026-10-20" source_commit: "1a6f2608ae302d613ac17ae8584c7239ae47044b" upstream_commit: "be32deab74b7778647273fa5616d1ea92e3e1267" -core_version: "1.0.1" +core_version: "v1.0.1" +version_basis: + kind: tag + tag: "v1.0.1" + distance: 0 display_name: "Clydeware - GameTank (GameTank)" cores: - gametank diff --git a/emulators/gargoyle.yml b/emulators/gargoyle.yml index a61c723f3..cff2a7db1 100644 --- a/emulators/gargoyle.yml +++ b/emulators/gargoyle.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/garglk/garglk" profiled_date: "2026-08-08" source_commit: "9e06211c20bee35026744424a57f50375cdc29db" core_version: "2026.1" +version_basis: + kind: file + path: "VERSION" + pattern: '^(\S+)' display_name: "Interactive Fiction (Gargoyle)" cores: - gargoyle diff --git a/emulators/gba-emu.yml b/emulators/gba-emu.yml index 223103328..a75fc36df 100644 --- a/emulators/gba-emu.yml +++ b/emulators/gba-emu.yml @@ -7,6 +7,10 @@ profiled_date: "2026-08-11" source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" upstream_commit: "46cc9f6bda114737e99304a4bd8427c038e63084" core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/metadata/conf.mk" + pattern: '^metadata_version\s*=\s*(\S+)' display_name: "Nintendo - Game Boy Advance (GBA.emu)" mode: standalone cores: diff --git a/emulators/gbc-emu.yml b/emulators/gbc-emu.yml index 55833963b..2be409fcf 100644 --- a/emulators/gbc-emu.yml +++ b/emulators/gbc-emu.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/sinamas/gambatte" profiled_date: "2026-08-11" source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/metadata/conf.mk" + pattern: '^metadata_version\s*=\s*(\S+)' display_name: "Nintendo - Game Boy / Color (GBC.emu)" mode: standalone cores: diff --git a/emulators/gearboy.yml b/emulators/gearboy.yml index cd6a624e9..d1a091cb3 100644 --- a/emulators/gearboy.yml +++ b/emulators/gearboy.yml @@ -5,7 +5,11 @@ source: "https://github.com/drhelius/Gearboy" upstream: "https://github.com/drhelius/Gearboy" profiled_date: "2026-03-23" source_commit: "b0a5fcaf68009c288d6b8016164a21af452d81b5" -core_version: "3.8.19" +core_version: "3.8.19-10-gb0a5fca" +version_basis: + kind: tag + tag: "3.8.19" + distance: 10 display_name: "Nintendo - Game Boy / Color (Gearboy)" cores: - gearboy diff --git a/emulators/gearcoleco.yml b/emulators/gearcoleco.yml index 719b262c2..72dd6fc61 100644 --- a/emulators/gearcoleco.yml +++ b/emulators/gearcoleco.yml @@ -5,7 +5,11 @@ source: "https://github.com/drhelius/Gearcoleco" upstream: "https://github.com/drhelius/Gearcoleco" profiled_date: "2026-09-17" source_commit: "be1a3716d2db312c1add1639753258e365f2dfd4" -core_version: "1.7.4-24-g23d0ec2" +core_version: "1.7.4-35-gbe1a371" +version_basis: + kind: tag + tag: "1.7.4" + distance: 35 display_name: "Coleco - ColecoVision / ADAM (Gearcoleco)" cores: - gearcoleco diff --git a/emulators/geargrafx.yml b/emulators/geargrafx.yml index ff8ca2848..dd5113f5b 100644 --- a/emulators/geargrafx.yml +++ b/emulators/geargrafx.yml @@ -5,7 +5,11 @@ source: "https://github.com/drhelius/Geargrafx" upstream: "https://github.com/drhelius/Geargrafx" profiled_date: "2026-10-04" source_commit: "7c447b0bd46b6085abdf1d685b49480f4a295c17" -core_version: "1.8.5" +core_version: "1.8.5-10-g7c447b0" +version_basis: + kind: tag + tag: "1.8.5" + distance: 10 display_name: "NEC - PC Engine / SuperGrafx / CD (Geargrafx)" cores: - geargrafx diff --git a/emulators/gearlynx.yml b/emulators/gearlynx.yml index bbcf38c33..cff689e09 100644 --- a/emulators/gearlynx.yml +++ b/emulators/gearlynx.yml @@ -4,7 +4,11 @@ core_classification: official_port source: "https://github.com/drhelius/Gearlynx" profiled_date: "2026-10-04" source_commit: "77901f3d3b318a12fdf71dd3ebb64048f0070ada" -core_version: "1.2.36" +core_version: "1.2.36-10-g77901f3" +version_basis: + kind: tag + tag: "1.2.36" + distance: 10 display_name: "Atari - Lynx (GearLynx)" cores: [gearlynx] systems: [atari-lynx] diff --git a/emulators/gearsystem.yml b/emulators/gearsystem.yml index f74e5880c..6539cc8b6 100644 --- a/emulators/gearsystem.yml +++ b/emulators/gearsystem.yml @@ -5,7 +5,11 @@ source: "https://github.com/drhelius/Gearsystem" upstream: "https://github.com/drhelius/Gearsystem" profiled_date: "2026-03-23" source_commit: "215c22f73d06871e12291025105c98470509468d" -core_version: "3.9.23" +core_version: "3.9.23-10-g215c22f" +version_basis: + kind: tag + tag: "3.9.23" + distance: 10 display_name: "Sega - MS/GG/SG-1000 (Gearsystem)" cores: - gearsystem diff --git a/emulators/geartowns.yml b/emulators/geartowns.yml index 21a5f9812..907ec2971 100644 --- a/emulators/geartowns.yml +++ b/emulators/geartowns.yml @@ -5,7 +5,11 @@ source: "https://github.com/drhelius/Geartowns" upstream: "https://github.com/drhelius/Geartowns" profiled_date: "2026-10-27" source_commit: "996d42b098bd572ba66a8246bfe56cee39e5ff6e" -core_version: "1.0.1" +core_version: "1.0.1-5-g996d42b" +version_basis: + kind: tag + tag: "1.0.1" + distance: 5 display_name: "Fujitsu - FM Towns (Geartowns)" cores: - "geartowns" diff --git a/emulators/gemrb.yml b/emulators/gemrb.yml index 535b6b38d..6ebb4e9ab 100644 --- a/emulators/gemrb.yml +++ b/emulators/gemrb.yml @@ -5,7 +5,11 @@ source: "https://github.com/gemrb/gemrb" upstream: "https://github.com/gemrb/gemrb" profiled_date: "2026-10-20" source_commit: "ef32a9a8b837ddf4f3a9508b23710146ada2d5fe" -core_version: "0.9.2" +core_version: "v0.9.2" +version_basis: + kind: tag + tag: "v0.9.2" + distance: 0 display_name: "Infinity Engine (GemRB)" cores: - gemrb diff --git a/emulators/genesis_plus_gx.yml b/emulators/genesis_plus_gx.yml index 3373db7d8..df78f744f 100644 --- a/emulators/genesis_plus_gx.yml +++ b/emulators/genesis_plus_gx.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-23" source_commit: "60bee4c724859710ce05672239e5b601ad01382e" upstream_commit: "c7ecd07f0a08db1cdd6871d788476bfac55be638" core_version: "v1.7.4" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Sega - MS/GG/MD/CD (Genesis Plus GX)" cores: - genesis_plus_gx diff --git a/emulators/genesis_plus_gx_expanded.yml b/emulators/genesis_plus_gx_expanded.yml index e5ca0821a..c84648943 100644 --- a/emulators/genesis_plus_gx_expanded.yml +++ b/emulators/genesis_plus_gx_expanded.yml @@ -7,6 +7,10 @@ profiled_date: "2026-10-23" source_commit: "dea3528cc0e3f54098e1fb91e3ae7e0e5d90a590" upstream_commit: "e366ca817f5b750ad06a8e2c5976d79b3758ea0a" core_version: "v1.7.4" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Sega - MS/GG/MD/CD (Genesis Plus GX Expanded)" cores: - genesis_plus_gx_expanded diff --git a/emulators/genesis_plus_gx_wide.yml b/emulators/genesis_plus_gx_wide.yml index 30fef45a3..dc34679b8 100644 --- a/emulators/genesis_plus_gx_wide.yml +++ b/emulators/genesis_plus_gx_wide.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-23" source_commit: "b7ad005431f5f0b55e559f6d598d1ed2479bf13b" upstream_commit: "f3cb0a5115a2b29426495ae35c2d45c404e650df" core_version: "v1.7.4" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Sega - MS/GG/MD/CD (Genesis Plus GX Wide)" cores: - genesis_plus_gx_wide diff --git a/emulators/geolith.yml b/emulators/geolith.yml index a5ff28bd1..b9c4c515e 100644 --- a/emulators/geolith.yml +++ b/emulators/geolith.yml @@ -6,7 +6,11 @@ upstream: "https://gitlab.com/jgemu/geolith" profiled_date: "2026-08-07" source_commit: "2dc88e3fa72ff404213a65d6eb5bb33baa687f73" upstream_commit: "05ddef568212e7225ceec22f3ecb20b5a9b640e6" -core_version: "0.4.1" +core_version: "0.5.0" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "SNK - Neo Geo AES/MVS (Geolith)" cores: - geolith diff --git a/emulators/ghostship.yml b/emulators/ghostship.yml index 0013f1adf..a2dd06aca 100644 --- a/emulators/ghostship.yml +++ b/emulators/ghostship.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/HarbourMasters/Ghostship" source_commit: "deb091c29caff57dd986398087b058f16b11911e" profiled_date: "2026-10-20" core_version: "3.0.0" +version_basis: + kind: tag + tag: "3.0.0" + distance: 0 display_name: "Super Mario 64 (Ghostship)" cores: [ghostship] systems: [ghostship] diff --git a/emulators/gme.yml b/emulators/gme.yml index c4b1b3c50..911e0b3c4 100644 --- a/emulators/gme.yml +++ b/emulators/gme.yml @@ -5,7 +5,12 @@ source: "https://github.com/libretro/libretro-gme" upstream: "https://github.com/libgme/game-music-emu" profiled_date: "2026-03-23" source_commit: "1562f6207a066e9807243c89648d1cb44e411971" -core_version: "Git" +core_version: "0.6.0" +version_basis: + kind: file + path: "deps/game-music-emu/gme/gme.h" + pattern: '#define\s+GME_VERSION\s+0x0?([0-9])0?([0-9])0?([0-9])\b' + format: "{1}.{2}.{3}" display_name: "Game Music Emu" cores: [gme] systems: [] diff --git a/emulators/gngeopi.yml b/emulators/gngeopi.yml index 55c20e78d..d73481531 100644 --- a/emulators/gngeopi.yml +++ b/emulators/gngeopi.yml @@ -4,7 +4,11 @@ core_classification: community_fork source: "https://github.com/ymartel06/GnGeo-Pi" profiled_date: "2026-10-20" source_commit: "b94571c6097b67cfc9db5eaffb98cdc8bcb55c6e" -core_version: "0.85" +core_version: "0.8" +version_basis: + kind: file + path: "gngeo/configure.in" + pattern: 'AC_INIT\(gngeo,\s*([^)\s]+)\)' display_name: "SNK - Neo Geo (GnGeo-Pi)" mode: standalone cores: diff --git a/emulators/gong.yml b/emulators/gong.yml index 8ff212780..066fe86e7 100644 --- a/emulators/gong.yml +++ b/emulators/gong.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/gong" upstream: "https://danzaidan.itch.io/" profiled_date: "2026-03-23" source_commit: "69ef0b69dc542af4c1cf2efcc451dd6c378281b6" -core_version: "1.0" +core_version: "v1.0" +version_basis: + kind: file + path: "gong.c" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "Gong" cores: [gong] systems: [] diff --git a/emulators/gopher2600.yml b/emulators/gopher2600.yml index 742c50099..ba38a7837 100644 --- a/emulators/gopher2600.yml +++ b/emulators/gopher2600.yml @@ -5,7 +5,11 @@ source: "https://github.com/JetSetIlly/Gopher2600" upstream: "https://github.com/JetSetIlly/Gopher2600" profiled_date: "2026-08-08" source_commit: "295b9e1c08203453677ea4184e284c0664f5949a" -core_version: "v0.57.0" +core_version: "v0.58.0" +version_basis: + kind: file + path: "Makefile" + pattern: '^version\s*=\s*(\S+)' display_name: "Atari - 2600 (Gopher2600)" cores: - gopher2600 diff --git a/emulators/gopher64.yml b/emulators/gopher64.yml index 2b0197fee..0440a049d 100644 --- a/emulators/gopher64.yml +++ b/emulators/gopher64.yml @@ -5,7 +5,11 @@ source: "https://github.com/gopher64/gopher64" upstream: "https://github.com/gopher64/gopher64" profiled_date: "2026-10-23" source_commit: "87385e77432cd278ac8588c7ed3d5014fc0d6bab" -core_version: "v1.1.42" +core_version: "1.1.42" +version_basis: + kind: file + path: "Cargo.toml" + pattern: 'version\s+=\s+"([^"]+)' display_name: "Nintendo - Nintendo 64 (gopher64)" cores: - gopher64 diff --git a/emulators/gpsp.yml b/emulators/gpsp.yml index 9ab548942..2de95d67a 100644 --- a/emulators/gpsp.yml +++ b/emulators/gpsp.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/gpsp" upstream: "https://github.com/davidgfnet/gpsp" profiled_date: "2026-03-23" source_commit: "5819380c2ffb0900219d700a382ee68c464ebb99" -core_version: "Git" +core_version: "v1.1.0" +version_basis: + kind: file + path: "gpsp_config.h" + pattern: '#define\s+GPSP_VERSION\s+"([^"]+)"' display_name: "Nintendo - Game Boy Advance (gpSP)" cores: - gpsp diff --git a/emulators/groovymame.yml b/emulators/groovymame.yml index f71fe652b..560d088c6 100644 --- a/emulators/groovymame.yml +++ b/emulators/groovymame.yml @@ -8,7 +8,11 @@ source_commit: "953db38f4aaab1d75faa4ac79e1b45686214f987" upstream_commit: "f34f02505e32c1993c6a782b6814232cbfc74e36" logo: "https://raw.githubusercontent.com/mamedev/mame/master/docs/source/images/MAMElogo.svg" profiled_date: "2026-10-26" -core_version: "0.289" +core_version: "gm0289sr222f" +version_basis: + kind: tag + tag: "gm0289sr222f" + distance: 0 display_name: "Arcade (GroovyMAME)" cores: diff --git a/emulators/gsplus-legacy.yml b/emulators/gsplus-legacy.yml index 8c12640b5..f63659cd7 100644 --- a/emulators/gsplus-legacy.yml +++ b/emulators/gsplus-legacy.yml @@ -8,6 +8,10 @@ profiled_date: "2026-10-20" source_commit: "480572054518112647c8fae5d7ea7046a6d6ecfb" pin_frozen: "Recalbox builds this commit (Recalbox package/gsplus/gsplus.mk:8-9 at tag 10.1.1). Batocera builds the applemu fork and RetroBat its release build, as the notes say." core_version: "0.14" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'project\(gsplus\s+VERSION\s+([0-9][\w.+-]*)' display_name: "Apple - Apple IIGS (GSplus legacy)" systems: - apple-iigs diff --git a/emulators/gsplus.yml b/emulators/gsplus.yml index cf6469ce1..911950623 100644 --- a/emulators/gsplus.yml +++ b/emulators/gsplus.yml @@ -5,7 +5,11 @@ source: "https://github.com/digarok/gsplus" upstream: "https://kegs.sourceforge.net/" profiled_date: "2026-03-29" source_commit: "41e71031debbde98e66ea5c5c67498e9b4726a6d" -core_version: "KEGS 1.38" +core_version: "1.38.0" +version_basis: + kind: file + path: "gsplus/src/CMakeLists.txt" + pattern: 'project\(gsplus\s+VERSION\s+([0-9][0-9.]*)' display_name: "Apple - Apple IIGS (GSplus)" cores: - gsplus diff --git a/emulators/gw.yml b/emulators/gw.yml index 9c4b0e606..4764d1354 100644 --- a/emulators/gw.yml +++ b/emulators/gw.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/gw-libretro" upstream: "http://www.madrigaldesign.it/sim/" profiled_date: "2026-03-25" source_commit: "91d599b951e7bfe7e040347f58667cba20074adc" -core_version: "Git" +core_version: "1.6.3" +version_basis: + kind: file + path: "src/libretro_version.c" + pattern: 'gw_version\s*=\s*"([^"]+)"' display_name: "Handheld Electronic (GW)" cores: - gw diff --git a/emulators/gzdoom.yml b/emulators/gzdoom.yml index 844fe3765..026507747 100644 --- a/emulators/gzdoom.yml +++ b/emulators/gzdoom.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/ZDoom/gzdoom" profiled_date: "2026-10-04" source_commit: "c26ce2e6ca2a0c770f140cb25dde0d30073ca8f7" core_version: "4.15pre" +version_basis: + kind: file + path: "src/version.h" + pattern: '#define\s+VERSIONSTR\s+"([^"]+)' display_name: "GZDoom" cores: ["GZDoom", "gzdoom-sa"] systems: [doom, heretic, hexen, strife, chex] diff --git a/emulators/hakux.yml b/emulators/hakux.yml index 9b56a189e..b8daffc28 100644 --- a/emulators/hakux.yml +++ b/emulators/hakux.yml @@ -7,7 +7,11 @@ author: "rfandango" profiled_date: "2026-08-11" source_commit: "e64e336d27dc8a56b67f441ec36bfddc1379cb6e" upstream_commit: "26fcbe54f17e496bdf530dad9f237e74e2f943fc" -core_version: "0.3.1" +core_version: "v0.3.1" +version_basis: + kind: tag + tag: "v0.3.1" + distance: 0 display_name: "Microsoft - Xbox (hakuX)" cores: - hakux diff --git a/emulators/handy.yml b/emulators/handy.yml index 91b6ba84c..55eafab8c 100644 --- a/emulators/handy.yml +++ b/emulators/handy.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/libretro-handy" upstream: "https://handy.sourceforge.net/" profiled_date: "2026-03-23" source_commit: "bc55d462f0b2d6b073ea93dc552ebd73cec60fd1" -core_version: "0.95" +core_version: "0.97" +version_basis: + kind: file + path: "libretro/handy.h" + pattern: '#define\s+HANDYVER\s+"([^"]+)"' display_name: "Atari - Lynx (Handy)" cores: - handy diff --git a/emulators/hatari.yml b/emulators/hatari.yml index 5c97c17ce..2930e467d 100644 --- a/emulators/hatari.yml +++ b/emulators/hatari.yml @@ -8,6 +8,10 @@ profiled_date: "2026-10-21" source_commit: "50929946d196f431906932420c55e1b3593dacc5" upstream_commit: "23bc3060ebf0da348cc842e358c102ba88002b56" core_version: "2.6.1-devel" +version_basis: + kind: file + path: "src/includes/version.h" + pattern: '^#define\s+HATARI_VERSION\s+"([^" ]+)' display_name: "Atari - ST/STE/TT/Falcon (Hatari)" cores: - hatari diff --git a/emulators/hatari2014.yml b/emulators/hatari2014.yml index 9e94a5f05..f9e2e2ecf 100644 --- a/emulators/hatari2014.yml +++ b/emulators/hatari2014.yml @@ -7,7 +7,12 @@ upstream: "https://github.com/hatari/hatari" profiled_date: "2026-09-03" source_commit: "ab55c3ed0e620c91e7f059a6d3fbef7acf9bfca8" upstream_commit: "c1a5c88bc06e56778b6b7f8483becfd58a7da2b4" -core_version: "1.8.0" +core_version: "v1.8.0" +version_basis: + kind: tag + repo: upstream + tag: "v1.8.0" + distance: 0 display_name: "Atari - ST/STE/TT/Falcon (Hatari 2014)" cores: - hatari2014 diff --git a/emulators/hatarib.yml b/emulators/hatarib.yml index fea3bbe43..502f6fec2 100644 --- a/emulators/hatarib.yml +++ b/emulators/hatarib.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/hatari/hatari" profiled_date: "2026-09-17" source_commit: "5f05733fc21903dce7d978bd0d7aae445ffe1185" upstream_commit: "23bc3060ebf0da348cc842e358c102ba88002b56" -core_version: "1.1 unstable preview" +core_version: "v1.1" +version_basis: + kind: file + path: "core/core.c" + pattern: '#define\s+CORE_VERSION\s+"([^" ]+)' display_name: "Atari - ST/STE/TT/Falcon (hatariB)" cores: - hatarib diff --git a/emulators/hbmame.yml b/emulators/hbmame.yml index 3a3a86b1e..33b99273e 100644 --- a/emulators/hbmame.yml +++ b/emulators/hbmame.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/Robbbert/hbmame" logo: "https://raw.githubusercontent.com/mamedev/mame/master/docs/source/images/MAMElogo.svg" profiled_date: "2026-03-23" source_commit: "840eeef5ee0fd75dab62c90bf25789b898f3dba3" -core_version: "Git" +core_version: "0.289" +version_basis: + kind: file + path: "makefile" + pattern: '^BARE_VERS\s*:=\s*(\S+)' display_name: "Arcade (HBMAME)" cores: - hbmame diff --git a/emulators/hcl.yml b/emulators/hcl.yml index 6c40618cb..d7691ffd5 100644 --- a/emulators/hcl.yml +++ b/emulators/hcl.yml @@ -5,7 +5,11 @@ source: "https://github.com/ptitSeb/hydracastlelabyrinth" upstream: "https://github.com/ptitSeb/hydracastlelabyrinth" profiled_date: "2026-10-04" source_commit: "e31648688434a789e3056e52cdf1b9a842eeed48" -core_version: ~ +core_version: "v0.1.0-4-ge316486" +version_basis: + kind: tag + tag: "v0.1.0" + distance: 4 display_name: "Hydra Castle Labyrinth (hcl)" cores: [hcl] systems: [] diff --git a/emulators/higan_sfc.yml b/emulators/higan_sfc.yml index 49eb06e11..476243f59 100644 --- a/emulators/higan_sfc.yml +++ b/emulators/higan_sfc.yml @@ -7,6 +7,10 @@ upstream: "https://gitlab.com/higan/higan" profiled_date: "2026-09-17" source_commit: "d3f592013a27cb78f17d84f90a6be6cf6f6af1d1" core_version: "106" +version_basis: + kind: file + path: "higan/emulator/emulator.hpp" + pattern: 'static\s+const\s+string\s+Version\s*=\s*"([^"]+)"' display_name: "Nintendo - SNES / Famicom (higan Accuracy)" cores: - higan_sfc diff --git a/emulators/higan_sfc_balanced.yml b/emulators/higan_sfc_balanced.yml index 67526a74b..6c88faec8 100644 --- a/emulators/higan_sfc_balanced.yml +++ b/emulators/higan_sfc_balanced.yml @@ -8,6 +8,10 @@ source_commit: "5b2b5da3a9654d88b2e51fb7a1637808ac601a18" upstream_commit: "3353efd3a1087f4d16d9b9fd2a8e465087ab8ec0" upstream_frozen: "nSide is synced with the higan v106r25 release, this commit. Later higan history is another program." core_version: "106.25" +version_basis: + kind: file + path: "nSide/emulator/emulator.hpp" + pattern: 'static\s+const\s+string\s+Version\s*=\s*"([^"]+)"' display_name: "Nintendo - SNES / SFC (nSide Balanced)" cores: - nside_sfc_balanced diff --git a/emulators/hode.yml b/emulators/hode.yml index 500526c9e..db6e30537 100644 --- a/emulators/hode.yml +++ b/emulators/hode.yml @@ -5,6 +5,10 @@ source: "https://github.com/usineur/hode" profiled_date: "2026-10-22" source_commit: "59f3c466923c6b8d49e29176ff697a91165e7efc" core_version: "0.2.9f" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'nacptool --create "[^"]*" "[^"]*" "([^"]+)"' display_name: "Heart of Darkness (hode)" cores: - "hode" diff --git a/emulators/holani.yml b/emulators/holani.yml index 04ec9d216..b24ff6ed7 100644 --- a/emulators/holani.yml +++ b/emulators/holani.yml @@ -7,6 +7,11 @@ profiled_date: "2026-10-27" source_commit: "d0d79b4928e3d32695294142784c033ce7aeda9b" upstream_commit: "7871f5cc6a26cf458f1adaaf54c4ccbd3ab3e338" core_version: "1.0.0" +version_basis: + kind: tag + repo: upstream + tag: "1.0.0" + distance: 0 display_name: "Atari - Lynx (Holani)" cores: [holani] systems: [atari-lynx] diff --git a/emulators/hurrican.yml b/emulators/hurrican.yml index 43d518712..8dcc13220 100644 --- a/emulators/hurrican.yml +++ b/emulators/hurrican.yml @@ -5,7 +5,11 @@ source: "https://github.com/HurricanGame/Hurrican" upstream: "https://github.com/HurricanGame/Hurrican" profiled_date: "2026-10-04" source_commit: "0d91d1f2d40f38d21e7f41afc01369ee55649fb6" -core_version: ~ +core_version: "v1.0.9.3-398-g0d91d1f" +version_basis: + kind: tag + tag: "v1.0.9.3" + distance: 398 display_name: "Hurrican" cores: [hurrican] systems: [] diff --git a/emulators/hypseus-singe.yml b/emulators/hypseus-singe.yml index c18965f59..261098e32 100644 --- a/emulators/hypseus-singe.yml +++ b/emulators/hypseus-singe.yml @@ -7,6 +7,10 @@ source_commit: "a16e2521ee3233ef20c44e562008c47f4b4293df" upstream_commit: "cd214c6046365047704f8a0563928970b30444e6" profiled_date: "2026-10-27" core_version: "v3.0.2" +version_basis: + kind: tag + tag: "v3.0.2" + distance: 0 display_name: "Arcade (Hypseus Singe)" cores: - hypseus-singe diff --git a/emulators/idtech4a++.yml b/emulators/idtech4a++.yml index 79573fe57..25130e05c 100644 --- a/emulators/idtech4a++.yml +++ b/emulators/idtech4a++.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/glKarin/com.n0n3m4.diii4a" author: "glKarin" profiled_date: "2026-09-17" source_commit: "ce49510f3b0c04969eab8ebe8238416e84e4f0bb" -core_version: "1.1.0harmattan73" +core_version: "v1.1.0harmattan73" +version_basis: + kind: tag + tag: "v1.1.0harmattan73" + distance: 0 display_name: "id Tech engine collection (idTech4A++)" cores: - "idtech4a++" diff --git a/emulators/ikemen.yml b/emulators/ikemen.yml index eda036bfd..a2c128ec9 100644 --- a/emulators/ikemen.yml +++ b/emulators/ikemen.yml @@ -5,7 +5,12 @@ source: "https://github.com/ikemen-engine/Ikemen-GO" upstream: "https://github.com/ikemen-engine/Ikemen-GO" profiled_date: "2026-10-04" source_commit: "e9bfe1125dea88769b265e57bcfaefdb22fa4322" -core_version: ~ +core_version: "v1.0.0-rc.1-545-ge9bfe11" +version_basis: + kind: tag + match: "v*" + tag: "v1.0.0-rc.1" + distance: 545 display_name: "Ikemen GO" cores: [ikemen] systems: [] diff --git a/emulators/imageviewer.yml b/emulators/imageviewer.yml index 9452a4ff6..62628ffc8 100644 --- a/emulators/imageviewer.yml +++ b/emulators/imageviewer.yml @@ -4,7 +4,11 @@ core_classification: pure_libretro source: "https://github.com/libretro/RetroArch/tree/master/cores/libretro-imageviewer" profiled_date: "2026-03-24" source_commit: "5078a39b624e31b359e1527ea7fbfddfc7de96cb" -core_version: "1.0" +core_version: "1.22.2" +version_basis: + kind: file + path: "version.all" + pattern: '#define\s+PACKAGE_VERSION\s+"([^"]+)"' display_name: "Imageviewer" cores: - imageviewer diff --git a/emulators/ines.yml b/emulators/ines.yml index 9066a47a3..fe94bcf5d 100644 --- a/emulators/ines.yml +++ b/emulators/ines.yml @@ -9,6 +9,10 @@ version_source: author: "Marat Fayzullin (Garage Research)" profiled_date: "2026-10-20" core_version: "6.1.12" +version_basis: + kind: package + url: "https://play.google.com/store/apps/details?id=com.fms.ines.free" + artifact: "com.fms.ines.free APK versionName (versionCode 6112)" display_name: "Nintendo - NES / Famicom (iNES)" cores: - ines diff --git a/emulators/infinity.yml b/emulators/infinity.yml index 127b94351..7a756ed86 100644 --- a/emulators/infinity.yml +++ b/emulators/infinity.yml @@ -10,6 +10,10 @@ version_source: author: "GuoPing He" profiled_date: "2026-08-11" core_version: "5" +version_basis: + kind: package + url: "https://play.google.com/store/apps/details?id=me.dt2dev.infinity" + artifact: "me.dt2dev.infinity APK versionName (versionCode 501)" display_name: "PICO-8 (Infinity)" cores: - infinity diff --git a/emulators/ioquake3.yml b/emulators/ioquake3.yml index acf8d129c..58020f253 100644 --- a/emulators/ioquake3.yml +++ b/emulators/ioquake3.yml @@ -5,7 +5,11 @@ source: "https://github.com/ioquake/ioq3" upstream: "https://github.com/ioquake/ioq3" profiled_date: "2026-10-04" source_commit: "87a99d18206e878a20289f05ac3c16005dcae5c3" -core_version: "1.36+git" +core_version: "1.36" +version_basis: + kind: file + path: "cmake/identity.cmake" + pattern: 'set\(PROJECT_VERSION\s+([^)\s]+)\)' display_name: "ioquake3" cores: [ioquake3] systems: [quake3, teamarena] diff --git a/emulators/iortcw.yml b/emulators/iortcw.yml index 1ec447039..7116d0f85 100644 --- a/emulators/iortcw.yml +++ b/emulators/iortcw.yml @@ -5,6 +5,11 @@ source: "https://github.com/iortcw/iortcw" upstream: "https://github.com/iortcw/iortcw" profiled_date: "2026-10-04" source_commit: "438e7d413b5f7277187c35b032eb0ef9093ae778" +core_version: "1.51d" +version_basis: + kind: file + path: "SP/Makefile" + pattern: '^VERSION=([0-9][^-\s]*)-SP' display_name: "ioRTCW" cores: [] systems: [return-to-castle-wolfenstein] diff --git a/emulators/iratajaguar.yml b/emulators/iratajaguar.yml index b40a36c2e..1917a6504 100644 --- a/emulators/iratajaguar.yml +++ b/emulators/iratajaguar.yml @@ -9,6 +9,11 @@ version_source: author: "Maxim Grishin (Altmer)" profiled_date: "2026-08-11" core_version: "1.0.7" +version_basis: + kind: package + url: "http://www.arts-union.ru/node/23" + pattern: 'IrataJaguar_free_(\d+(?:\.\d+)+)\.zip' + artifact: "IrataJaguar_free_1.0.7.zip" display_name: "Atari - Jaguar (IrataJaguar)" cores: - iratajaguar diff --git a/emulators/irogb.yml b/emulators/irogb.yml index 96bc9d655..4db88ce13 100644 --- a/emulators/irogb.yml +++ b/emulators/irogb.yml @@ -5,7 +5,11 @@ source: "https://github.com/AlexSutila/IroGB" upstream: "https://github.com/AlexSutila/IroGB" profiled_date: "2026-09-03" source_commit: "7b6bb9b1f9cbf04e49eea0dc89c54635c2b54056" -core_version: "1.0.0" +core_version: "v1.0.0" +version_basis: + kind: file + path: "src/frontend/libretro/libretro_host.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Nintendo - Game Boy / Color (IroGB)" cores: - irogb diff --git a/emulators/ishiiruka.yml b/emulators/ishiiruka.yml index 1c4f4d24b..5077d64ef 100644 --- a/emulators/ishiiruka.yml +++ b/emulators/ishiiruka.yml @@ -6,7 +6,9 @@ upstream: "https://github.com/Tinob/Ishiiruka" profiled_date: "2026-03-24" source_commit: "f228bde5fbf4861ba749a229803addcd6238663f" upstream_commit: "cba6d7279b44894297d8c1dde1effdbba3605c32" -core_version: "Git" +core_version: null +version_basis: + kind: none display_name: "Nintendo - GameCube / Wii (Ishiiruka)" library_name: "Ishiiruka" cores: diff --git a/emulators/izapple2.yml b/emulators/izapple2.yml index 58b69eba4..e01c623ea 100644 --- a/emulators/izapple2.yml +++ b/emulators/izapple2.yml @@ -5,7 +5,11 @@ source: "https://github.com/ivanizag/izapple2" upstream: "https://github.com/ivanizag/izapple2" profiled_date: "2026-08-08" source_commit: "4e773baf9f1f3fb692e3f3444eb5f42fddb205ef" -core_version: "v2.5.0" +core_version: "v2.5.0-3-g4e773ba" +version_basis: + kind: tag + tag: "v2.5.0" + distance: 3 display_name: "Apple - Apple II (izapple2)" cores: - izapple2 diff --git a/emulators/j2me-loader.yml b/emulators/j2me-loader.yml index 33f79785d..f1df6771e 100644 --- a/emulators/j2me-loader.yml +++ b/emulators/j2me-loader.yml @@ -7,6 +7,10 @@ author: "Nikita Shakarun" profiled_date: "2026-10-23" source_commit: "76383ebf348b5d477256fc884dfc55f053b45a86" core_version: "1.8.2" +version_basis: + kind: file + path: "app/build.gradle" + pattern: 'versionName\s+"([^"]+)' display_name: "Mobile - J2ME (J2ME Loader)" cores: - j2me-loader diff --git a/emulators/jaxe.yml b/emulators/jaxe.yml index a30826091..2903f0db7 100644 --- a/emulators/jaxe.yml +++ b/emulators/jaxe.yml @@ -5,7 +5,11 @@ source: "https://github.com/kurtjd/jaxe" upstream: "https://github.com/kurtjd/jaxe" profiled_date: "2026-03-24" source_commit: "c767afd785e01a15bcd575a2d93b737add82b675" -core_version: "GIT" +core_version: "1.0" +version_basis: + kind: file + path: "src/libretro.c" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "CHIP-8/S-CHIP/XO-CHIP (JAXE)" cores: - jaxe diff --git a/emulators/jazz2-native.yml b/emulators/jazz2-native.yml index df891231e..8e5972a45 100644 --- a/emulators/jazz2-native.yml +++ b/emulators/jazz2-native.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/deathkiller/jazz2-native" profiled_date: "2026-10-04" source_commit: "ff9ddb7be9c84bdcf71b22d9380da06135edeb62" core_version: "3.9.0" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'set\(NCINE_VERSION\s+"([^"]+)"\)' display_name: "Jazz Jackrabbit 2 (Jazz² Resurrection)" cores: [jazz2] systems: [jazz-jackrabbit-2] diff --git a/emulators/jgenesis.yml b/emulators/jgenesis.yml index 579ea3a12..20fe6fdad 100644 --- a/emulators/jgenesis.yml +++ b/emulators/jgenesis.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/jsgroth/jgenesis" profiled_date: "2026-08-08" source_commit: "0a00c47ba7a16bd6e77ef7e0b6c8fab2fc603cba" core_version: "0.14.1" +version_basis: + kind: file + path: "Cargo.toml" + pattern: 'version\s+=\s+"([^"]+)' display_name: "Multi-System (jgenesis)" cores: - jgenesis diff --git a/emulators/jl-mod.yml b/emulators/jl-mod.yml index a8aee96d1..927a98b9a 100644 --- a/emulators/jl-mod.yml +++ b/emulators/jl-mod.yml @@ -8,6 +8,10 @@ profiled_date: "2026-08-11" source_commit: "f723a190c0bdb44b31c3bc0ead6f8665c7ea517d" upstream_commit: "76383ebf348b5d477256fc884dfc55f053b45a86" core_version: "0.87.1" +version_basis: + kind: file + path: "app/build.gradle.kts" + pattern: 'versionName\s+=\s+"([^"]+)' display_name: "Mobile - J2ME (JL-Mod)" cores: - jl-mod diff --git a/emulators/jollycv.yml b/emulators/jollycv.yml index ef37d8e71..9c74ff459 100644 --- a/emulators/jollycv.yml +++ b/emulators/jollycv.yml @@ -7,6 +7,10 @@ profiled_date: "2026-09-17" source_commit: "2790d59c7194d29e83f8603ffd7e9da17f11575e" upstream_commit: "3caacb22143543d5c7de4f3208def645a2ec0ab5" core_version: "2.1.0" +version_basis: + kind: file + path: "version.h" + pattern: '#define\s+JG_VERSION\s+"([^"]+)' display_name: "ColecoVision/CreatiVision/My Vision (JollyCV)" cores: - jollycv diff --git a/emulators/julius.yml b/emulators/julius.yml index 40a235cab..504f3d47b 100644 --- a/emulators/julius.yml +++ b/emulators/julius.yml @@ -5,7 +5,12 @@ source: "https://github.com/bvschaik/julius" upstream: "https://github.com/bvschaik/julius" profiled_date: "2026-10-17" source_commit: "34d1ecd54befb845c0139b371fa8a0438210dac1" -core_version: "v1.8.0" +core_version: "1.8.0" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'set\(PROJECT_VERSION_MAJOR (\d+)\)\s*\nset\(PROJECT_VERSION_MINOR (\d+)\)\s*\nset\(PROJECT_VERSION_PATCH (\d+)\)' + format: "{1}.{2}.{3}" display_name: "Caesar III (Julius)" cores: - "julius" diff --git a/emulators/jumpnbump.yml b/emulators/jumpnbump.yml index 8f428e943..53adc6fb4 100644 --- a/emulators/jumpnbump.yml +++ b/emulators/jumpnbump.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/jumpnbump-libretro" upstream: "https://github.com/fabiangreffrath/jumpnbump" profiled_date: "2026-03-24" source_commit: "2cc840155ce4bf42b2e9e0ef3854b32d534e607e" -core_version: "v0.1" +core_version: "0.1" +version_basis: + kind: file + path: "libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Jump 'n Bump" cores: [jumpnbump] systems: [] diff --git a/emulators/jynx.yml b/emulators/jynx.yml index 05c82f717..3acc894d6 100644 --- a/emulators/jynx.yml +++ b/emulators/jynx.yml @@ -4,7 +4,11 @@ core_classification: other source: "https://github.com/jonathan-markland/Jynx" profiled_date: "2026-10-20" source_commit: "c1247f2c957b78d3ca6f2b814ee346a298f3573c" -core_version: "1.0.8" +core_version: "v1.0.8" +version_basis: + kind: tag + tag: "v1.0.8" + distance: 0 display_name: "Camputers - Lynx (Jynx)" cores: - jynx diff --git a/emulators/jzintv.yml b/emulators/jzintv.yml index b34f27c35..c35eb8ddd 100644 --- a/emulators/jzintv.yml +++ b/emulators/jzintv.yml @@ -8,6 +8,11 @@ version_source: pattern: 'jzintv-(\d{8})-src\.zip' profiled_date: "2026-10-20" core_version: "20200712" +version_basis: + kind: package + url: "http://spatula-city.org/~im14u2c/intv/" + pattern: 'jzintv-(\d{8})-src\.zip' + artifact: "jzintv-20200712-src.zip" display_name: "Mattel - Intellivision (jzIntv)" cores: - jzintv diff --git a/emulators/kega-fusion.yml b/emulators/kega-fusion.yml index 3b17be7eb..cf81fc678 100644 --- a/emulators/kega-fusion.yml +++ b/emulators/kega-fusion.yml @@ -6,6 +6,10 @@ upstream: closed-source author: "Steve Snake" profiled_date: "2026-10-20" core_version: "3.64" +version_basis: + kind: package + url: "https://www.retrobat.ovh/repo/win64/stable/emulators/kega-fusion.7z" + artifact: "kega-fusion.7z, Fusion.exe banner" display_name: "Sega - Master System / Mega Drive / Mega CD / 32X (Kega Fusion)" cores: - kega-fusion diff --git a/emulators/kegs.yml b/emulators/kegs.yml index 9293527db..783eae855 100644 --- a/emulators/kegs.yml +++ b/emulators/kegs.yml @@ -8,6 +8,11 @@ version_source: pattern: 'Download the KEGS v(\d+\.\d+) zip' profiled_date: "2026-08-08" core_version: "1.38" +version_basis: + kind: package + url: "https://kegs.sourceforge.net/kegs.1.38.zip" + pattern: 'kegs\.(\d+\.\d+)\.zip' + artifact: "kegs.1.38.zip" display_name: "Apple - Apple IIGS (KEGS)" cores: - kegs diff --git a/emulators/kemulator.yml b/emulators/kemulator.yml index bf884f844..9b77503d1 100644 --- a/emulators/kemulator.yml +++ b/emulators/kemulator.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/shinovon/KEmulator" author: "shinovon" profiled_date: "2026-08-11" source_commit: "1ab219907cfcac0e6313d1b6ccba13ad74015d08" -core_version: "v2.22" +core_version: "2.22" +version_basis: + kind: file + path: "src/main/emulator/Emulator.java" + pattern: 'public static String version = "([^"]+)"' display_name: "Mobile - J2ME (KEmulator nnmod)" cores: - kemulator diff --git a/emulators/kenji-nx.yml b/emulators/kenji-nx.yml index 9c9c60a5e..9cbf4c8ec 100644 --- a/emulators/kenji-nx.yml +++ b/emulators/kenji-nx.yml @@ -7,6 +7,9 @@ upstream: "https://git.ryujinx.app/projects/Ryubing" profiled_date: "2026-08-11" source_commit: "53d32a761e61dc8e9b5c0744199a890fc8d934d5" core_version: "2.1.0-pr.2" +version_basis: + kind: unverified + why: host_unreachable display_name: "Nintendo - Switch (Kenji-NX)" cores: - kenji-nx diff --git a/emulators/kronos.yml b/emulators/kronos.yml index 4f55dc454..f5cf0a6dc 100644 --- a/emulators/kronos.yml +++ b/emulators/kronos.yml @@ -7,7 +7,11 @@ upstream: "https://github.com/FCare/Kronos" profiled_date: "2026-03-24" source_commit: "3791ffb2221fda61d70aec5cca376418caf05669" upstream_commit: "d0384bc33aad06bfa9cf5cd308c4bd7ae6cfc814" -core_version: "v2.6.0" +core_version: "2.7.0" +version_basis: + kind: file + path: "yabause/src/libretro/Makefile.common" + pattern: '-DVERSION=\\"([^\\"]+)\\"' display_name: "Sega - Saturn/ST-V (Kronos)" cores: - kronos diff --git a/emulators/lexaloffle.yml b/emulators/lexaloffle.yml index ef12e99e6..2ee407462 100644 --- a/emulators/lexaloffle.yml +++ b/emulators/lexaloffle.yml @@ -2,6 +2,10 @@ emulator: Lexaloffle type: standalone upstream: "https://www.lexaloffle.com/" profiled_date: "2026-03-26" +core_version: null +version_basis: + kind: unverified + why: no_artifact display_name: "Lexaloffle - PICO-8 / Voxatron" cores: - lexaloffle diff --git a/emulators/lightspark.yml b/emulators/lightspark.yml index e2b7a07c1..18a5852f1 100644 --- a/emulators/lightspark.yml +++ b/emulators/lightspark.yml @@ -6,6 +6,11 @@ upstream: "https://github.com/lightspark/lightspark" profiled_date: "2026-08-08" source_commit: "6f07fd65cb95b88ff73e905bf78a1a8b1ddf6049" core_version: "0.10.0" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'SET\(MAJOR_VERSION "(\d+)"\)\s*\nSET\(MINOR_VERSION "(\d+)"\)\s*\nSET\(PATCH_VERSION "(\d+)"\)' + format: "{1}.{2}.{3}" display_name: "Adobe Flash (Lightspark)" cores: - lightspark diff --git a/emulators/lime3ds.yml b/emulators/lime3ds.yml index 7cfe2e447..04d5ef794 100644 --- a/emulators/lime3ds.yml +++ b/emulators/lime3ds.yml @@ -5,7 +5,11 @@ source: "https://github.com/Lime3DS/lime3ds-archive" upstream: "https://github.com/Lime3DS/lime3ds-archive" profiled_date: "2026-08-08" source_commit: "c9dbb5bb40d90dfa6a2b085d152ae6ecf915b2f9" -core_version: "2119.1" +core_version: "2119.1-2-gc9dbb5b" +version_basis: + kind: tag + tag: "2119.1" + distance: 2 display_name: "Nintendo - 3DS (Lime3DS)" cores: - lime3ds diff --git a/emulators/linapple.yml b/emulators/linapple.yml index 094537ba2..fb57da131 100644 --- a/emulators/linapple.yml +++ b/emulators/linapple.yml @@ -7,6 +7,10 @@ profiled_date: "2026-10-20" source_commit: "7f4b60898d91bfecd6f4d8683a374f38b0564962" upstream_commit: "9970ef6b668a7cf057ce6d82f100dde6a751f4d3" core_version: "3.0.0" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'project\(linapple\s+VERSION\s+([0-9][\w.+-]*)' display_name: "Apple - Apple II (LinApple)" cores: - linapple diff --git a/emulators/lindbergh-loader.yml b/emulators/lindbergh-loader.yml index 48b55b29e..b2a746158 100644 --- a/emulators/lindbergh-loader.yml +++ b/emulators/lindbergh-loader.yml @@ -5,7 +5,12 @@ source: "https://github.com/lindbergh-loader/lindbergh-loader" upstream: "https://github.com/lindbergh-loader/lindbergh-loader" source_commit: "0af606d845b70339c335785c0eba68b47b78df3c" profiled_date: "2026-08-08" -core_version: "2.1.4" +core_version: "2.0.0" +version_basis: + kind: file + path: "src/lindbergh/version.h" + pattern: '#define MAJOR_VERSION (\d+)\s*\n#define MINOR_VERSION (\d+)\s*\n#define UPDATE_VERSION (\d+)' + format: "{1}.{2}.{3}" display_name: "Sega - Lindbergh (Lindbergh Loader)" cores: - lindbergh-loader diff --git a/emulators/linkboy.yml b/emulators/linkboy.yml index 7f7e2680d..3a7b18261 100644 --- a/emulators/linkboy.yml +++ b/emulators/linkboy.yml @@ -9,6 +9,10 @@ version_source: author: "Pixel Respawn LLC" profiled_date: "2026-10-24" core_version: "4.0.0" +version_basis: + kind: package + url: "https://play.google.com/store/apps/details?id=com.pixelrespawn.linkboy" + artifact: "com.pixelrespawn.linkboy APK versionName (versionCode 95)" display_name: "Nintendo - Game Boy / Color / Advance (Linkboy)" mode: standalone cores: diff --git a/emulators/linuxloader.yml b/emulators/linuxloader.yml index 30b50640a..220dceb93 100644 --- a/emulators/linuxloader.yml +++ b/emulators/linuxloader.yml @@ -5,7 +5,11 @@ source: "https://github.com/lindbergh-loader/linuxloader" upstream: "https://github.com/lindbergh-loader/linuxloader" source_commit: "9aa6e3e45ccfbbc60eb0f975aa9d3d158a13706c" profiled_date: "2026-10-20" -core_version: "3.0.12" +core_version: "v3.0.12" +version_basis: + kind: tag + tag: "v3.0.12" + distance: 0 display_name: "Sega - Lindbergh (Linux Loader)" cores: - linuxloader diff --git a/emulators/love-0.10.2.yml b/emulators/love-0.10.2.yml index e8f6344a9..ca41ff412 100644 --- a/emulators/love-0.10.2.yml +++ b/emulators/love-0.10.2.yml @@ -7,6 +7,10 @@ profiled_date: "2026-10-20" source_commit: "9e139779956ddba89333eece8104bd7b1b4ff2e7" pin_frozen: "RetroPie, the only platform that ships it, builds the 0.10.2 tag at this commit (RetroPie scriptmodules/ports/love-0.10.2.sh:16). Later releases are packaged separately as love." core_version: "0.10.2" +version_basis: + kind: tag + tag: "0.10.2" + distance: 0 display_name: "LOVE 2D game framework (0.10.2)" cores: - love-0.10.2 diff --git a/emulators/love.yml b/emulators/love.yml index 8f195e8c9..3aa22fce8 100644 --- a/emulators/love.yml +++ b/emulators/love.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/love2d/love" profiled_date: "2026-10-20" source_commit: "6eb8d546736d5915a8b5af30b2cf33456dfdcb1a" core_version: "11.5" +version_basis: + kind: tag + tag: "11.5" + distance: 0 display_name: "LOVE 2D game framework" cores: - love diff --git a/emulators/lowresnx.yml b/emulators/lowresnx.yml index 38439c489..6d666d5b6 100644 --- a/emulators/lowresnx.yml +++ b/emulators/lowresnx.yml @@ -5,7 +5,11 @@ source: "https://github.com/timoinutilis/lowres-nx" upstream: "https://github.com/timoinutilis/lowres-nx" profiled_date: "2026-03-25" source_commit: "63d5988f74e1eea2ecd6ea0445a8ce260b0a9822" -core_version: "v1.2" +core_version: "1.2" +version_basis: + kind: file + path: "core/core.h" + pattern: '#define\s+CORE_VERSION\s+"([^"]+)"' display_name: "LowRes NX" cores: - lowresnx diff --git a/emulators/lrps2.yml b/emulators/lrps2.yml index 1740b9a97..8977a465b 100644 --- a/emulators/lrps2.yml +++ b/emulators/lrps2.yml @@ -11,7 +11,11 @@ upstream: "https://github.com/PCSX2/pcsx2" profiled_date: "2026-10-21" source_commit: "8c2b679622d602fe656ceba646b2f1f3a981c717" upstream_commit: "f0523f8acb1d3a765ee73b74cffec63093569199" -core_version: "Git" +core_version: "v2.0.0" +version_basis: + kind: file + path: "libretro/main.cpp" + pattern: 'library_version\s*=\s*"(v[0-9.]+)-"' display_name: "Sony - PlayStation 2 (LRPS2)" cores: [lrps2, pcsx2, "ps2"] systems: [sony-playstation-2] diff --git a/emulators/lutro.yml b/emulators/lutro.yml index d0456d82e..4e7a54482 100644 --- a/emulators/lutro.yml +++ b/emulators/lutro.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/libretro-lutro" upstream: "https://github.com/libretro/libretro-lutro" profiled_date: "2026-03-24" source_commit: "6224157a615b18507bc0b117a3398c7a324cd3e5" -core_version: "v1" +core_version: "0.0.1" +version_basis: + kind: file + path: "lutro.h" + pattern: '#define\s+VERSION_STRING\s+"([^"]+)"' display_name: "Lua Engine (Lutro)" cores: - lutro diff --git a/emulators/lynx-emu.yml b/emulators/lynx-emu.yml index eefcc55a3..d37d37c76 100644 --- a/emulators/lynx-emu.yml +++ b/emulators/lynx-emu.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-08-11" source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/metadata/conf.mk" + pattern: '^metadata_version\s*=\s*(\S+)' display_name: "Atari - Lynx (Lynx.emu)" mode: standalone cores: diff --git a/emulators/lzdoom.yml b/emulators/lzdoom.yml index c29441683..8ca3a0e57 100644 --- a/emulators/lzdoom.yml +++ b/emulators/lzdoom.yml @@ -6,6 +6,10 @@ profiled_date: "2026-10-20" source_commit: "4ce19a12164ebd6802b7fb2f94d700a6e736d0fb" pin_frozen: "The platforms that ship it run the 3.88 line: RetroPie builds tag 3.88b (RetroPie scriptmodules/ports/lzdoom.sh:15) and AmberELEC a fork of the g3.3mgw branch that still reports 3.88b (AmberELEC packages/games/emulators/lzdoom/package.mk:5). The l4.x releases are a GZDoom 4 based line that no platform ships." core_version: "3.88b" +version_basis: + kind: tag + tag: "3.88b" + distance: 0 display_name: "LZDoom" cores: [lzdoom, "LZDoom"] systems: [doom, heretic, hexen, strife, chex] diff --git a/emulators/m2000.yml b/emulators/m2000.yml index 8216cd1a2..c84009985 100644 --- a/emulators/m2000.yml +++ b/emulators/m2000.yml @@ -5,7 +5,11 @@ source: "https://github.com/p2000t/M2000" upstream: "https://github.com/p2000t/M2000" profiled_date: "2026-03-24" source_commit: "da0b8cbef2007c907f5db2166847c3209643865d" -core_version: "0.9.4" +core_version: "0.9.5" +version_basis: + kind: file + path: "src/P2000.h" + pattern: '#define\s+EMULATOR_VERSION\s+"([^"]+)"' display_name: "Philips - P2000T (M2000)" cores: - m2000 diff --git a/emulators/m64plus-fz.yml b/emulators/m64plus-fz.yml index b6215173e..a58a793fb 100644 --- a/emulators/m64plus-fz.yml +++ b/emulators/m64plus-fz.yml @@ -7,6 +7,10 @@ source_branch: fz-master profiled_date: "2026-08-11" source_commit: "f3c381bcc58e4adce897aba323193d3f407e30e3" core_version: "3.0.335 (beta)" +version_basis: + kind: file + path: "build_common/version_common.gradle" + pattern: 'versionName\s*=\s*"([^"]+)"' display_name: "Nintendo - Nintendo 64 (M64Plus FZ)" cores: - m64plus-fz diff --git a/emulators/magicengine.yml b/emulators/magicengine.yml index 4df3ff8ab..20c2d0a5e 100644 --- a/emulators/magicengine.yml +++ b/emulators/magicengine.yml @@ -6,6 +6,10 @@ upstream: closed-source author: "David Michel, Cedric Michel" profiled_date: "2026-10-20" core_version: "1.1.3" +version_basis: + kind: package + url: "https://www.retrobat.ovh/repo/win64/stable/emulators/magicengine.7z" + artifact: "magicengine.7z, readme.txt" display_name: "NEC - PC Engine / CD-ROM / SuperGrafx (MagicEngine)" cores: - magicengine diff --git a/emulators/mame.yml b/emulators/mame.yml index 8b305eb2f..c35f61500 100644 --- a/emulators/mame.yml +++ b/emulators/mame.yml @@ -8,6 +8,10 @@ profiled_date: "2026-03-29" source_commit: "5f5a07748ce5c239c4118463ce8e6473743d4859" upstream_commit: "f34f02505e32c1993c6a782b6814232cbfc74e36" core_version: "0.289" +version_basis: + kind: file + path: "makefile" + pattern: '#define BARE_BUILD_VERSION "([^"]+)"' display_name: "Arcade (MAME)" cores: diff --git a/emulators/mame0258.yml b/emulators/mame0258.yml index 552715571..9420c9fd8 100644 --- a/emulators/mame0258.yml +++ b/emulators/mame0258.yml @@ -7,7 +7,11 @@ profiled_date: '2026-10-22' source_commit: dc1a96537089d6d4ecd01d9886b21061471c70c0 upstream_commit: 2e0aa823508663c4a27164be43467d1ef740cdcd pin_frozen: 'Recalbox, the only platform that ships it, builds this revision (Recalbox package/libretro-mame0258/libretro-mame0258.mk:8 at tag 10.1.1). Later commits are not part of that build.' -core_version: '0.258' +core_version: "0.258" +version_basis: + kind: file + path: "makefile" + pattern: '#define BARE_BUILD_VERSION "([^"]+)"' display_name: Arcade (MAME 0.258) cores: - mame0258 diff --git a/emulators/mame0278.yml b/emulators/mame0278.yml index ba1390e6b..ce20e9276 100644 --- a/emulators/mame0278.yml +++ b/emulators/mame0278.yml @@ -7,7 +7,11 @@ profiled_date: '2026-10-22' source_commit: fba50741006fa3e27e1897f589d2048a505b8fd6 upstream_commit: eb05584a2b8d98d5af5587244c9cb7dcccf660fd pin_frozen: 'Recalbox, the only platform that ships it, builds this revision (Recalbox package/libretro-mame0278/libretro-mame0278.mk:8 at tag 10.1.1). Later commits are not part of that build.' -core_version: '0.278' +core_version: "0.278" +version_basis: + kind: file + path: "makefile" + pattern: '#define BARE_BUILD_VERSION "([^"]+)"' display_name: Arcade (MAME 0.278) cores: - mame0278 diff --git a/emulators/mame2000.yml b/emulators/mame2000.yml index a29ae3bc7..a9e514da5 100644 --- a/emulators/mame2000.yml +++ b/emulators/mame2000.yml @@ -6,6 +6,10 @@ upstream: "https://www.mamedev.org" profiled_date: "2026-03-24" source_commit: "181b42e5da0d2f0c7a2e59244f23633ed594de2e" core_version: "0.37b5" +version_basis: + kind: file + path: "src/libretro/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Arcade (MAME 2000)" cores: diff --git a/emulators/mame2003.yml b/emulators/mame2003.yml index a425c113c..5078311bd 100644 --- a/emulators/mame2003.yml +++ b/emulators/mame2003.yml @@ -6,6 +6,10 @@ upstream: "https://www.mamedev.org" profiled_date: "2026-03-24" source_commit: "b9ac708f922386a0ae1f2379dbb31b60d7ec7b25" core_version: "0.78" +version_basis: + kind: file + path: "src/mame2003/mame2003.c" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "Arcade (MAME 2003)" cores: diff --git a/emulators/mame2003_midway.yml b/emulators/mame2003_midway.yml index 414255694..d0580e995 100644 --- a/emulators/mame2003_midway.yml +++ b/emulators/mame2003_midway.yml @@ -6,6 +6,10 @@ upstream: "https://www.mamedev.org" profiled_date: "2026-03-24" source_commit: "fb5fb047d0efd9fdc9d56e50fa377f5e47569d35" core_version: "0.78" +version_basis: + kind: file + path: "src/libretro/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Arcade (MAME 2003 Midway)" cores: diff --git a/emulators/mame2003_plus.yml b/emulators/mame2003_plus.yml index 331c30bf2..e8ca9c588 100644 --- a/emulators/mame2003_plus.yml +++ b/emulators/mame2003_plus.yml @@ -6,7 +6,9 @@ upstream: "https://www.mamedev.org" logo: "https://raw.githubusercontent.com/mamedev/mame/master/docs/source/images/MAMElogo.svg" profiled_date: "2026-03-24" source_commit: "993403d0332946b8aa6abab56fbd9864498790a1" -core_version: "2003-Plus" +core_version: null +version_basis: + kind: none display_name: "Arcade (MAME 2003-Plus)" mame_version: "0.78 (plus backports)" diff --git a/emulators/mame2009.yml b/emulators/mame2009.yml index 1f034cc6b..e6d3dfe33 100644 --- a/emulators/mame2009.yml +++ b/emulators/mame2009.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-24" source_commit: "45048806fbc0fea82709a75a523f2eda945e0a47" upstream_commit: "c285eb9bcd3505c14a338e29f251ba00776cc75c" core_version: "0.135u4" +version_basis: + kind: file + path: "src/version.c" + pattern: 'build_version\[\]\s*=\s*"([^" ]+)' display_name: "Arcade (MAME 2009)" cores: diff --git a/emulators/mame2010.yml b/emulators/mame2010.yml index b4b3de5c4..660d7e629 100644 --- a/emulators/mame2010.yml +++ b/emulators/mame2010.yml @@ -8,6 +8,10 @@ profiled_date: "2026-03-22" source_commit: "dff8aadd1c3f38215af3955746d6e19abe0ddcea" upstream_commit: "f4f24ba7274010fb8ccb84548b5ca95c2be2f85b" core_version: "0.139" +version_basis: + kind: file + path: "src/osd/retro/retroos.c" + pattern: 'const char build_version\[\]\s*=\s*"([^" ]+)' display_name: "Arcade (MAME 2010)" mame_version: "0.139" diff --git a/emulators/mame2014.yml b/emulators/mame2014.yml index 8c894187c..a0d023ada 100644 --- a/emulators/mame2014.yml +++ b/emulators/mame2014.yml @@ -8,9 +8,13 @@ profiled_date: "2026-10-20" source_commit: "c8fe6c7399f24466808b67933b2b96feea188e0b" upstream_commit: "0147bb4cc82e642cf75151f039f240eb20989fbc" pin_frozen: "RetroBat, the only platform that ships it, distributes a build of this revision: the mame2014_libretro.dll of its win64 stable core repository reports library_version \"0.160 c8fe6c7\". Later commits are not part of that build." -core_version: "0.160" +core_version: "0.159" +version_basis: + kind: file + path: "src/version.c" + pattern: '#define\s+BARE_BUILD_VERSION\s+"([^"]+)"' display_name: "Arcade (MAME 2014)" -mame_version: "0.160" +mame_version: "0.159" cores: - mame2014 @@ -89,7 +93,7 @@ notes: | reports library_version "0.160 c8fe6c7" and library_name "MAME 2014", so this profile reads the tree at c8fe6c7. - Same MAME 0.160 code as mame2015: between c8fe6c7 and the mame2015 pin no + Same MAME 0.159 code as mame2015 (version.c): between c8fe6c7 and the mame2015 pin no driver ROM definition, romload.c or hiscore.c changes. What differs is the directory name. libretro_shared.h sets core to "mame2014", and Set_Path_Option builds samples, artwork, cheat, ini and hash under diff --git a/emulators/mame2015.yml b/emulators/mame2015.yml index 390206d4f..8a8216a08 100644 --- a/emulators/mame2015.yml +++ b/emulators/mame2015.yml @@ -7,9 +7,13 @@ logo: "https://raw.githubusercontent.com/mamedev/mame/master/docs/source/images/ profiled_date: "2026-03-24" source_commit: "7adbf440d5f554097f58f8c6ebb673adc4320a31" upstream_commit: "0147bb4cc82e642cf75151f039f240eb20989fbc" -core_version: "0.160" +core_version: "0.159" +version_basis: + kind: file + path: "src/version.c" + pattern: '#define\s+BARE_BUILD_VERSION\s+"([^"]+)"' display_name: "Arcade (MAME 2015)" -mame_version: "0.160" +mame_version: "0.159" cores: - mame2015 @@ -80,14 +84,15 @@ systems: - barcrest-mpu4 notes: | - Frozen snapshot of MAME 0.160 (mid-2015). 69 BIOS root sets. Upstream + Frozen snapshot of MAME 0.159 (version.c says 0.159, the core reports + 0.160). 69 BIOS root sets. Upstream comparison (tag mame0160): BIOS root sets identical, romload.c unmodified. hiscore.c added (not in upstream), per-game XML cheat support via cheat_path(). Paths under system_dir/mame2015/ (samples, artwork, cheat, hash). hiscore.dat loaded via f.open("hiscore", ".dat") without explicit search path (libretro-specific path code disabled via #if 0). - ROM naming follows MAME 0.160 conventions. + ROM naming follows the BIOS root sets of tag mame0160, identical here. files: # Data files diff --git a/emulators/mame2016.yml b/emulators/mame2016.yml index 4dba2460b..28e9a8fcf 100644 --- a/emulators/mame2016.yml +++ b/emulators/mame2016.yml @@ -8,6 +8,10 @@ profiled_date: "2026-03-22" source_commit: "ae07c2f88ff2482ba9f50ffc8c9e7e6fbfe97d0a" upstream_commit: "68785dccfee3208163c8169abc5c6d01becf36d4" core_version: "0.174" +version_basis: + kind: file + path: "src/version.cpp" + pattern: '#define\s+BARE_BUILD_VERSION\s+"([^"]+)' cores: - mame2016 diff --git a/emulators/mame4all.yml b/emulators/mame4all.yml index 77c8d1716..4856d7b22 100644 --- a/emulators/mame4all.yml +++ b/emulators/mame4all.yml @@ -5,7 +5,11 @@ source: "https://github.com/RetroPie/mame4all-pi" upstream: "https://sourceforge.net/projects/mame4allpi/" profiled_date: "2026-10-20" source_commit: "c6bfd2aef331b5a5e157c15d8bf8a77393c85689" -core_version: "0.37b5" +core_version: "0.37 BETA 5" +version_basis: + kind: file + path: "src/version.cpp" + pattern: 'build_version\[\]\s*=\s*"(.+?) \("' display_name: "Arcade (MAME4ALL-Pi)" mode: standalone cores: diff --git a/emulators/mame4droid-2024.yml b/emulators/mame4droid-2024.yml index 539d07c48..8400e2993 100644 --- a/emulators/mame4droid-2024.yml +++ b/emulators/mame4droid-2024.yml @@ -7,7 +7,11 @@ logo: "https://raw.githubusercontent.com/mamedev/mame/master/docs/source/images/ profiled_date: "2026-08-11" source_commit: "32d781923fc0fb7621f3d78903f1b37fd4a5694a" upstream_commit: "f34f02505e32c1993c6a782b6814232cbfc74e36" -core_version: "1.38.1" +core_version: "v1.38.1" +version_basis: + kind: tag + tag: "v1.38.1" + distance: 0 display_name: "Arcade (MAME4droid 2024)" mame_version: "0.289" diff --git a/emulators/mame4droid-current.yml b/emulators/mame4droid-current.yml index 1a3d5b225..d08f09fe2 100644 --- a/emulators/mame4droid-current.yml +++ b/emulators/mame4droid-current.yml @@ -7,7 +7,11 @@ upstream: "https://github.com/mamedev/mame/tree/mame0289" profiled_date: "2026-08-11" source_commit: "32d781923fc0fb7621f3d78903f1b37fd4a5694a" upstream_commit: "f34f02505e32c1993c6a782b6814232cbfc74e36" -core_version: "1.38.1" +core_version: "v1.38.1" +version_basis: + kind: tag + tag: "v1.38.1" + distance: 0 display_name: "Arcade (MAME4droid Current)" cores: diff --git a/emulators/mame4droid.yml b/emulators/mame4droid.yml index 06e84c83a..d2dec9ee7 100644 --- a/emulators/mame4droid.yml +++ b/emulators/mame4droid.yml @@ -8,6 +8,10 @@ profiled_date: "2026-08-11" source_commit: "9e4f9a36a65dd355ca9e28b1df3ef22a2c81d3a1" upstream_commit: "f4f24ba7274010fb8ccb84548b5ca95c2be2f85b" core_version: "0.139u1" +version_basis: + kind: file + path: "src/version.c" + pattern: 'build_version\[\]\s*=\s*"([^" ]+)' display_name: "Arcade (MAME4droid)" mame_version: "0.139u1" diff --git a/emulators/mamearcade.yml b/emulators/mamearcade.yml index 006f19b3b..1eea839c2 100644 --- a/emulators/mamearcade.yml +++ b/emulators/mamearcade.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-24" source_commit: "5f5a07748ce5c239c4118463ce8e6473743d4859" upstream_commit: "f34f02505e32c1993c6a782b6814232cbfc74e36" core_version: "0.289" +version_basis: + kind: file + path: "makefile" + pattern: '#define BARE_BUILD_VERSION "([^"]+)"' display_name: "Arcade (MAME/Arcade)" cores: diff --git a/emulators/mamemess.yml b/emulators/mamemess.yml index 46e3090d2..7bfd1f9d4 100644 --- a/emulators/mamemess.yml +++ b/emulators/mamemess.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/mamedev/mame" profiled_date: "2026-03-29" source_commit: "5f5a07748ce5c239c4118463ce8e6473743d4859" upstream_commit: "f34f02505e32c1993c6a782b6814232cbfc74e36" -core_version: "0.287" +core_version: "0.289" +version_basis: + kind: file + path: "makefile" + pattern: '#define BARE_BUILD_VERSION "([^"]+)"' display_name: "Multi (MAME/MESS)" cores: diff --git a/emulators/mandarine.yml b/emulators/mandarine.yml index 3a68a9a78..cabf6b861 100644 --- a/emulators/mandarine.yml +++ b/emulators/mandarine.yml @@ -5,7 +5,11 @@ source: "https://github.com/ptyfyre/mandarine-neo" upstream: "https://github.com/ptyfyre/mandarine-neo" profiled_date: "2026-08-08" source_commit: "7f8ec960b6183be4350bca099d23ddd9fc7bcaa3" -core_version: "1.3.0" +core_version: "r1.3.0-6-g7f8ec96" +version_basis: + kind: tag + tag: "r1.3.0" + distance: 6 display_name: "Nintendo - 3DS (Mandarine)" cores: - mandarine diff --git a/emulators/mariani.yml b/emulators/mariani.yml index 747b12370..b574804b9 100644 --- a/emulators/mariani.yml +++ b/emulators/mariani.yml @@ -7,6 +7,10 @@ profiled_date: "2026-08-12" source_commit: "51893cab7e8a3d1298734848f4fd616f2e1831fb" upstream_commit: "3e8054b4627624398e4589f7f27b3d40a6b9718e" core_version: "1.7" +version_basis: + kind: file + path: "Mariani.xcodeproj/project.pbxproj" + pattern: "MARKETING_VERSION = ([^;]+);" display_name: "Apple - Apple II (Mariani)" cores: - mariani diff --git a/emulators/mastergear.yml b/emulators/mastergear.yml index 99519ecff..824418703 100644 --- a/emulators/mastergear.yml +++ b/emulators/mastergear.yml @@ -10,6 +10,10 @@ version_source: author: "Marat Fayzullin (Garage Research)" profiled_date: "2026-08-12" core_version: "4.9" +version_basis: + kind: package + url: "https://play.google.com/store/apps/details?id=com.fms.mg" + artifact: "com.fms.mg APK versionName (versionCode 4900)" display_name: "Sega - Master System / Game Gear (MasterGear)" cores: - mastergear diff --git a/emulators/mcsoftserve.yml b/emulators/mcsoftserve.yml index 2be6b2ed2..101bd798a 100644 --- a/emulators/mcsoftserve.yml +++ b/emulators/mcsoftserve.yml @@ -5,6 +5,10 @@ source: "https://github.com/JesseTG/McSoftServe" profiled_date: "2026-03-24" source_commit: "fbdd09c7dfc11e35d900e51086f63e7f853e6c01" core_version: "1.0.0" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'project\("McSoftServe"\s*\n\s*VERSION "([^"]+)"' display_name: "McSoftServe" cores: - mcsoftserve diff --git a/emulators/md-emu.yml b/emulators/md-emu.yml index bfc4fb35b..abbc45760 100644 --- a/emulators/md-emu.yml +++ b/emulators/md-emu.yml @@ -7,6 +7,10 @@ profiled_date: "2026-08-12" source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" upstream_commit: "f3cb0a5115a2b29426495ae35c2d45c404e650df" core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/metadata/conf.mk" + pattern: '^metadata_version\s*=\s*(\S+)' display_name: "Sega - MS/MD/CD (MD.emu)" mode: standalone cores: diff --git a/emulators/mednafen.yml b/emulators/mednafen.yml index 2053f6b6f..5cdc34595 100644 --- a/emulators/mednafen.yml +++ b/emulators/mednafen.yml @@ -8,6 +8,11 @@ version_source: pattern: '<li><b>Mednafen (\d+(?:\.\d+)+)</b>' profiled_date: "2026-08-08" core_version: "1.32.1" +version_basis: + kind: package + url: "https://mednafen.github.io/releases/files/mednafen-1.32.1.tar.xz" + pattern: 'mednafen-(\d+(?:\.\d+)+)\.tar\.xz' + artifact: "mednafen-1.32.1.tar.xz" display_name: "Mednafen" cores: [mednafen] mode: standalone diff --git a/emulators/mednafen_gba.yml b/emulators/mednafen_gba.yml index 619352ea3..d8d3deaee 100644 --- a/emulators/mednafen_gba.yml +++ b/emulators/mednafen_gba.yml @@ -3,6 +3,9 @@ type: alias alias_of: "beetle_gba" profiled_date: "2026-03-24" core_version: "v0.9.36" +version_basis: + kind: alias + of: "beetle_gba" display_name: "Nintendo - Game Boy Advance (Beetle GBA)" cores: - mednafen_gba diff --git a/emulators/mednafen_lynx.yml b/emulators/mednafen_lynx.yml index 8cbe2ac90..b40c5620d 100644 --- a/emulators/mednafen_lynx.yml +++ b/emulators/mednafen_lynx.yml @@ -3,6 +3,9 @@ type: alias alias_of: "beetle_lynx" profiled_date: "2026-03-24" core_version: "v1.24.0" +version_basis: + kind: alias + of: "beetle_lynx" display_name: "Atari - Lynx (Beetle Lynx)" cores: - mednafen_lynx diff --git a/emulators/mednafen_ngp.yml b/emulators/mednafen_ngp.yml index 408ef2e03..0afaf8e37 100644 --- a/emulators/mednafen_ngp.yml +++ b/emulators/mednafen_ngp.yml @@ -3,6 +3,9 @@ type: alias alias_of: "beetle_ngp" profiled_date: "2026-03-24" core_version: "v1.29.0.0" +version_basis: + kind: alias + of: "beetle_ngp" display_name: "SNK - Neo Geo Pocket / Color (Beetle NeoPop)" cores: - mednafen_ngp diff --git a/emulators/mednafen_pce.yml b/emulators/mednafen_pce.yml index 257a68920..d83519043 100644 --- a/emulators/mednafen_pce.yml +++ b/emulators/mednafen_pce.yml @@ -3,6 +3,9 @@ type: alias alias_of: "beetle_pce" profiled_date: "2026-03-24" core_version: "v1.29.0" +version_basis: + kind: alias + of: "beetle_pce" display_name: "NEC - PC Engine / SuperGrafx / CD (Beetle PCE)" cores: - mednafen_pce diff --git a/emulators/mednafen_pce_fast.yml b/emulators/mednafen_pce_fast.yml index 67014859f..91e2e0acc 100644 --- a/emulators/mednafen_pce_fast.yml +++ b/emulators/mednafen_pce_fast.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-03-24" source_commit: "4eee99c451f85ebe66d1591de88b892015b23059" core_version: "v1.31.0.0" +version_basis: + kind: file + path: "libretro.c" + pattern: '#define\s+MEDNAFEN_CORE_VERSION\s+"([^"]+)' display_name: "NEC - PC Engine / CD (Beetle PCE FAST)" cores: [mednafen_pce_fast, pce_fast, beetle_pce_fast, "beetle-pce-fast"] systems: [nec-pc-engine] diff --git a/emulators/mednafen_pcfx.yml b/emulators/mednafen_pcfx.yml index 1739c42c3..9db6618cf 100644 --- a/emulators/mednafen_pcfx.yml +++ b/emulators/mednafen_pcfx.yml @@ -3,6 +3,9 @@ type: alias alias_of: "beetle_pcfx" profiled_date: "2026-03-24" core_version: "v0.9.36.5" +version_basis: + kind: alias + of: "beetle_pcfx" display_name: "NEC - PC-FX (Beetle PC-FX)" cores: - mednafen_pcfx diff --git a/emulators/mednafen_psx.yml b/emulators/mednafen_psx.yml index 72928feef..1b5bd75f0 100644 --- a/emulators/mednafen_psx.yml +++ b/emulators/mednafen_psx.yml @@ -2,7 +2,10 @@ emulator: "mednafen_psx" type: alias alias_of: "beetle_psx" profiled_date: "2026-03-24" -core_version: "v0.9.44.1" +core_version: "0.9.44.1" +version_basis: + kind: alias + of: "beetle_psx" display_name: "Sony - PlayStation (Beetle PSX)" cores: - mednafen_psx diff --git a/emulators/mednafen_psx_hw.yml b/emulators/mednafen_psx_hw.yml index f0ce68dfc..7b712fa27 100644 --- a/emulators/mednafen_psx_hw.yml +++ b/emulators/mednafen_psx_hw.yml @@ -2,7 +2,10 @@ emulator: "mednafen_psx_hw" type: alias alias_of: "beetle_psx" profiled_date: "2026-03-24" -core_version: "v0.9.44.1" +core_version: "0.9.44.1" +version_basis: + kind: alias + of: "beetle_psx" display_name: "Sony - PlayStation (Beetle PSX HW)" cores: - mednafen_psx_hw diff --git a/emulators/mednafen_saturn.yml b/emulators/mednafen_saturn.yml index eef662942..3d13c15f5 100644 --- a/emulators/mednafen_saturn.yml +++ b/emulators/mednafen_saturn.yml @@ -2,7 +2,10 @@ emulator: "mednafen_saturn" type: alias alias_of: "beetle_saturn" profiled_date: "2026-03-24" -core_version: "v0.9.45.1" +core_version: "v1.32.1" +version_basis: + kind: alias + of: "beetle_saturn" display_name: "Sega - Saturn (Beetle Saturn)" cores: - mednafen_saturn diff --git a/emulators/mednafen_snes.yml b/emulators/mednafen_snes.yml index 18eaae576..5cc78a905 100644 --- a/emulators/mednafen_snes.yml +++ b/emulators/mednafen_snes.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-03-24" source_commit: "5f05e4c785e936c928ac468e129c55b6f08592cb" core_version: "v0.9.26" +version_basis: + kind: file + path: "libretro.cpp" + pattern: '#define\s+MEDNAFEN_CORE_VERSION\s+"([^"]+)' display_name: "Nintendo - SNES / SFC (Beetle bsnes)" cores: [mednafen_snes, beetle_bsnes, beetle-bsnes, "beetle_snes"] systems: [nintendo-snes] diff --git a/emulators/mednafen_stv.yml b/emulators/mednafen_stv.yml index 19fd3bed0..1df2f03fa 100644 --- a/emulators/mednafen_stv.yml +++ b/emulators/mednafen_stv.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-10-27" source_commit: "e65713478870dd494afd5c0bcd852fc76c383f14" core_version: "v1.8.3" +version_basis: + kind: tag + tag: "v1.8.3" + distance: 0 display_name: "Sega - ST-V (Mednafen STV)" cores: - "mednafen_stv" diff --git a/emulators/mednafen_supafaust.yml b/emulators/mednafen_supafaust.yml index ed67ba7df..924621992 100644 --- a/emulators/mednafen_supafaust.yml +++ b/emulators/mednafen_supafaust.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-03-24" source_commit: "642d1d1b6684aa7e306a02a89885f3f5456a5157" core_version: "1.29.0" +version_basis: + kind: file + path: "mednafen/config.h" + pattern: '#define\s+MEDNAFEN_VERSION\s+"([^"]+)"' display_name: "Nintendo - SNES / SFC (Beetle Supafaust)" cores: [mednafen_supafaust, supafaust, beetle_supafaust] systems: [nintendo-snes] diff --git a/emulators/mednafen_supergrafx.yml b/emulators/mednafen_supergrafx.yml index 1f4349a3e..c91fd512d 100644 --- a/emulators/mednafen_supergrafx.yml +++ b/emulators/mednafen_supergrafx.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-10-04" source_commit: "9c11dcd213a79d57d2c86313971631af801f2cdc" core_version: "v1.29.0" +version_basis: + kind: file + path: "libretro.cpp" + pattern: '#define\s+MEDNAFEN_CORE_VERSION\s+"([^"]+)' display_name: "NEC - PC Engine SuperGrafx (Beetle SuperGrafx)" cores: [mednafen_supergrafx, beetle_supergrafx, "beetle-supergrafx"] systems: [nec-pc-engine] diff --git a/emulators/mednafen_vb.yml b/emulators/mednafen_vb.yml index b432c290a..34ba982ab 100644 --- a/emulators/mednafen_vb.yml +++ b/emulators/mednafen_vb.yml @@ -2,7 +2,10 @@ emulator: "mednafen_vb" type: alias alias_of: "beetle_vb" profiled_date: "2026-03-24" -core_version: "v0.9.36.1" +core_version: "v1.31.0" +version_basis: + kind: alias + of: "beetle_vb" display_name: "Nintendo - Virtual Boy (Beetle VB)" cores: - mednafen_vb diff --git a/emulators/mednafen_wswan.yml b/emulators/mednafen_wswan.yml index d82bcc4d8..c51252939 100644 --- a/emulators/mednafen_wswan.yml +++ b/emulators/mednafen_wswan.yml @@ -4,6 +4,9 @@ alias_of: "beetle_wswan" source: "https://github.com/libretro/beetle-wswan-libretro" profiled_date: "2026-03-24" core_version: "v0.9.35.1" +version_basis: + kind: alias + of: "beetle_wswan" display_name: "Bandai - WonderSwan/Color (Beetle Wonderswan)" cores: - mednafen_wswan diff --git a/emulators/melonds-nightly.yml b/emulators/melonds-nightly.yml index 076121ead..40f1df258 100644 --- a/emulators/melonds-nightly.yml +++ b/emulators/melonds-nightly.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/rafaelvcaetano/melonDS-android-lib" source_commit: "c42995caff0144f37ad9791dc9bc96d82e8a6f65" upstream_commit: "431ab4bd0003c4356e25fce89640ae1004579b9b" profiled_date: "2026-08-12" -core_version: "2.0.1 (NIGHTLY)" +core_version: "2.0.1" +version_basis: + kind: file + path: "buildSrc/src/main/kotlin/AppConfig.kt" + pattern: 'const val versionName = "([^"]+)"' display_name: "Nintendo - DS (melonDS Nightly)" cores: ["melonds-nightly"] systems: [nintendo-ds, nintendo-dsi] diff --git a/emulators/melonds.yml b/emulators/melonds.yml index 5915887a0..432e036a9 100644 --- a/emulators/melonds.yml +++ b/emulators/melonds.yml @@ -7,7 +7,11 @@ upstream: "https://github.com/melonDS-emu/melonDS" profiled_date: "2026-03-24" source_commit: "66b5d2634cd0a79030562811e6e05f5532f800ba" upstream_commit: "7d8dea42e221b13521270c423b61add41a741b97" -core_version: "Git" +core_version: "0.9.3" +version_basis: + kind: file + path: "Makefile.common" + pattern: '^MELONDS_VERSION\s*=\s*"([^"]+)"' display_name: "Nintendo - DS (melonDS)" systems: [nintendo-ds, nintendo-dsi] data_root: diff --git a/emulators/melonds_ds.yml b/emulators/melonds_ds.yml index 95f4ac6ec..d6605bf00 100644 --- a/emulators/melonds_ds.yml +++ b/emulators/melonds_ds.yml @@ -7,7 +7,11 @@ upstream: "https://github.com/melonDS-emu/melonDS" profiled_date: "2026-10-04" source_commit: "f394adbacb5722ee97c1b37c8064da9a25818310" upstream_commit: "7d8dea42e221b13521270c423b61add41a741b97" -core_version: "1.4.0" +core_version: "v1.4.0" +version_basis: + kind: tag + tag: "v1.4.0" + distance: 0 display_name: "Nintendo - DS (melonDS DS)" systems: - nintendo-ds diff --git a/emulators/mesen-s.yml b/emulators/mesen-s.yml index 79fc15434..f964611c9 100644 --- a/emulators/mesen-s.yml +++ b/emulators/mesen-s.yml @@ -11,6 +11,11 @@ profiled_date: "2026-03-24" source_commit: "9e4fdeb9b336470bc96beb8765b2e79c86a2da1e" upstream_commit: "89199f298a95345a893d814525b6668567a6d490" core_version: "0.4.0" +version_basis: + kind: file + path: "Core/EmuSettings.cpp" + pattern: 'uint16_t major = (\d+);\s*\n\s*uint8_t minor = (\d+);\s*\n\s*uint8_t revision = (\d+);' + format: "{1}.{2}.{3}" cores: [mesen-s, mesen_s] systems: [nintendo-snes, nintendo-gb, nintendo-gbc, nintendo-super-game-boy, nintendo-satellaview] diff --git a/emulators/mesen.yml b/emulators/mesen.yml index dc39a92d8..54eb463e8 100644 --- a/emulators/mesen.yml +++ b/emulators/mesen.yml @@ -7,6 +7,11 @@ logo: "https://raw.githubusercontent.com/SourMesen/Mesen2/master/UI/Assets/Mesen profiled_date: "2026-03-24" source_commit: "0102910c39ad1a62bc3f784466f3f67ca9eae335" core_version: "0.9.9" +version_basis: + kind: file + path: "Core/EmulationSettings.cpp" + pattern: '_versionMajor = (\d+);\s*\n[^\n]*_versionMinor = (\d+);\s*\n[^\n]*_versionRevision = (\d+);' + format: "{1}.{2}.{3}" display_name: "Nintendo - NES / Famicom (Mesen)" cores: [mesen, mesens] systems: [nintendo-nes, nintendo-fds] diff --git a/emulators/mesence.yml b/emulators/mesence.yml index 2aa0fbfc8..88480f7ca 100644 --- a/emulators/mesence.yml +++ b/emulators/mesence.yml @@ -12,7 +12,18 @@ source_commit: upstream_commit: "b9fa69ddc6d0a331fb103fdb5eef6904305703c2" core_version: standalone: "2.2.1" - libretro: "2.0.0" + libretro: "2.2.1" +version_basis: + standalone: + kind: file + path: "Core/Shared/EmuSettings.cpp" + pattern: 'uint16_t major = (\d+);\s*\n\s*uint8_t minor = (\d+);\s*\n\s*uint8_t revision = (\d+);' + format: "{1}.{2}.{3}" + libretro: + kind: file + path: "Core/Shared/EmuSettings.cpp" + pattern: 'uint16_t major = (\d+);\s*\n\s*uint8_t minor = (\d+);\s*\n\s*uint8_t revision = (\d+);' + format: "{1}.{2}.{3}" display_name: "Multi-System (MesenCE)" cores: [mesence, mesen2] systems: diff --git a/emulators/mess2015.yml b/emulators/mess2015.yml index 9b513f60c..63e8bb184 100644 --- a/emulators/mess2015.yml +++ b/emulators/mess2015.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/mame2015-libretro" upstream: "https://github.com/mamedev/mame/tree/mame0160" profiled_date: "2026-03-24" source_commit: "7adbf440d5f554097f58f8c6ebb673adc4320a31" -core_version: "0.160" +core_version: "0.159" +version_basis: + kind: file + path: "src/version.c" + pattern: '#define\s+BARE_BUILD_VERSION\s+"([^"]+)"' display_name: "Multi (MESS 2015)" mame_version: "0.159" diff --git a/emulators/meteor.yml b/emulators/meteor.yml index 274fdc20d..c735484af 100644 --- a/emulators/meteor.yml +++ b/emulators/meteor.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/blastrock/meteor" profiled_date: "2026-03-24" source_commit: "9ea6c358eae6acd1a346647d96b832ccaffad0aa" core_version: "v1.4" +version_basis: + kind: file + path: "libretro/libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Nintendo - Game Boy Advance (Meteor)" cores: - meteor diff --git a/emulators/mfme.yml b/emulators/mfme.yml index 6e5cabfa4..96d373a11 100644 --- a/emulators/mfme.yml +++ b/emulators/mfme.yml @@ -5,6 +5,10 @@ source: "https://www.desertislandfruits.com/" upstream: closed-source profiled_date: "2026-08-08" core_version: "20.1" +version_basis: + kind: package + url: "https://www.desertislandfruits.com/" + artifact: "MFME v20 Windows installer, MFME.exe FileVersion 20.1.0.0" display_name: "MFME (Fruit Machines)" cores: - mfme diff --git a/emulators/mgba.yml b/emulators/mgba.yml index 168c35045..30663a7fd 100644 --- a/emulators/mgba.yml +++ b/emulators/mgba.yml @@ -7,7 +7,12 @@ logo: "https://raw.githubusercontent.com/mgba-emu/mgba/master/res/mgba-256.png" profiled_date: "2026-03-24" source_commit: "7a12d6d4b9acb14c0ae62c9166b6a2f3d08007f6" upstream_commit: "669817d03e4858e65d0b992bcd96d3009236cc1e" -core_version: "0.10-dev" +core_version: "0.11.0" +version_basis: + kind: file + path: "version.cmake" + pattern: 'set\(LIB_VERSION_MAJOR (\d+)\)\s*\nset\(LIB_VERSION_MINOR (\d+)\)\s*\nset\(LIB_VERSION_PATCH (\d+)\)' + format: "{1}.{2}.{3}" display_name: "Nintendo - Game Boy Advance (mGBA)" cores: - mgba diff --git a/emulators/mgba_splitscreen.yml b/emulators/mgba_splitscreen.yml index df26841dc..9ef5e075a 100644 --- a/emulators/mgba_splitscreen.yml +++ b/emulators/mgba_splitscreen.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/mgba-emu/mgba" profiled_date: "2026-10-04" source_commit: "f1d5975d77285f77affbfe64b7050ebd5c4b6a77" upstream_commit: "afd6f14eaf8bd35214ed3fb9dc69a92bfc3877a9" -core_version: "v0.3.1" +core_version: "0.3.1" +version_basis: + kind: file + path: "mgba-splitscreen/package.json" + pattern: '"version":\s+"([^"]+)' display_name: "Nintendo - Game Boy Advance (mGBA Splitscreen)" cores: - mgba_splitscreen diff --git a/emulators/minivmac.yml b/emulators/minivmac.yml index 28685811c..4922ccf27 100644 --- a/emulators/minivmac.yml +++ b/emulators/minivmac.yml @@ -6,6 +6,10 @@ upstream: "https://www.gryphel.com/c/minivmac/" profiled_date: "2026-03-24" source_commit: "babdf7b53d361a7225858b68a8a64efe8b06f5e5" core_version: "36.04" +version_basis: + kind: file + path: "minivmac/cfg/CNFGRAPI.h" + pattern: '#define\s+kAppVariationStr\s+"minivmac-([0-9.]+)-' display_name: "Mac II (minivmac)" cores: [minivmac] systems: [macintosh-ii] diff --git a/emulators/minivmac37.yml b/emulators/minivmac37.yml index 089bf95fd..5ba128d50 100644 --- a/emulators/minivmac37.yml +++ b/emulators/minivmac37.yml @@ -5,6 +5,11 @@ source: "https://github.com/minivmac/minivmac" profiled_date: "2026-10-20" source_commit: "6860a9a7f372c461b25dc42974b191a453ebcfb2" core_version: "37.03" +version_basis: + kind: file + path: "setup/SPBASDEF.i" + pattern: '#define MajorVersion (\d+)\s*\n#define MinorVersion (\d+)' + format: "{1}.{2}" display_name: "Apple - Macintosh Plus (Mini vMac 37)" mode: standalone cores: ["minivmac"] diff --git a/emulators/mkxp-z.yml b/emulators/mkxp-z.yml index fa70b77db..6c2ae571e 100644 --- a/emulators/mkxp-z.yml +++ b/emulators/mkxp-z.yml @@ -5,4 +5,8 @@ display_name: "RPG Maker XP/VX/VX Ace (mkxp-z)" cores: - mkxp-z profiled_date: "2026-03-24" +core_version: "2.4.2" +version_basis: + kind: alias + of: "mkxp_z" files: [] diff --git a/emulators/mkxp_z.yml b/emulators/mkxp_z.yml index 8502f7178..d86b42710 100644 --- a/emulators/mkxp_z.yml +++ b/emulators/mkxp_z.yml @@ -8,7 +8,11 @@ upstream: "https://github.com/mkxp-z/mkxp-z" profiled_date: "2026-03-24" source_commit: "650cb0888a07d0b5044e131160ddfa53feaf595b" upstream_commit: "37a04d14413454551a7b6aadbb4e93e67168accb" -core_version: "f4bc5aa" +core_version: "2.4.2" +version_basis: + kind: file + path: "meson.build" + pattern: '^project\(\s*''mkxp-z''[^)]*?version:\s*''([^'']+)''' display_name: "RPG Maker XP/VX/VX Ace (mkxp-z)" cores: - mkxp-z diff --git a/emulators/model2.yml b/emulators/model2.yml index 4f4f69ca1..6c13c2335 100644 --- a/emulators/model2.yml +++ b/emulators/model2.yml @@ -7,6 +7,9 @@ version_source: pattern: 'Model 2 Emulator: (\d+\.\d+[a-z]?)' profiled_date: "2026-03-26" core_version: "1.1a" +version_basis: + kind: unverified + why: no_artifact display_name: "Model 2 Emulator (Sega Model 2)" cores: - model2 diff --git a/emulators/mojozork.yml b/emulators/mojozork.yml index 71dc3a689..c960f396f 100644 --- a/emulators/mojozork.yml +++ b/emulators/mojozork.yml @@ -5,7 +5,11 @@ source: "https://github.com/icculus/mojozork" upstream: "https://github.com/icculus/mojozork" profiled_date: "2026-03-24" source_commit: "ff7e00742a00acec8e175ddefb97520fb270df2d" -core_version: "0.1" +core_version: "0.3" +version_basis: + kind: file + path: "mojozork-libretro.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "Infocom Z-Machine (MojoZork)" cores: - mojozork diff --git a/emulators/moonlight.yml b/emulators/moonlight.yml index 225fe4ff1..78aefe552 100644 --- a/emulators/moonlight.yml +++ b/emulators/moonlight.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/moonlight-stream/moonlight-embedded" profiled_date: "2026-03-24" source_commit: "20d2d77d219613a2809fa9afe9606f6cf3be2aa0" core_version: "1.0.3" +version_basis: + kind: tag + tag: "1.0.3" + distance: 0 display_name: "Moonlight" cores: - moonlight diff --git a/emulators/mpv.yml b/emulators/mpv.yml index d1676222d..ecb0e6546 100644 --- a/emulators/mpv.yml +++ b/emulators/mpv.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/mpv-player/mpv" profiled_date: "2026-03-24" source_commit: "99f7fe4fd43d68da45006301829eaf37c7edbcc2" core_version: "0.2.alpha" +version_basis: + kind: file + path: "version.h" + pattern: '#define\s+LIBRETRO_MPV_VERSION\s+"([^"]+)' display_name: "MPV" cores: - mpv diff --git a/emulators/mrboom.yml b/emulators/mrboom.yml index 67e604d9d..ca771e6f7 100644 --- a/emulators/mrboom.yml +++ b/emulators/mrboom.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/mrboom-libretro" upstream: "https://github.com/libretro/mrboom-libretro" profiled_date: "2026-03-24" source_commit: "40ac32020b540c4bb418c7d798a990932a65da04" -core_version: "5.3" +core_version: "5.5" +version_basis: + kind: file + path: "common.hpp" + pattern: '#define\s+GAME_VERSION\s+"([^"]+)"' display_name: "Mr.Boom (Bomberman)" cores: [mrboom] systems: [] diff --git a/emulators/msx-emu.yml b/emulators/msx-emu.yml index d6b7135db..8a16aa246 100644 --- a/emulators/msx-emu.yml +++ b/emulators/msx-emu.yml @@ -6,6 +6,10 @@ upstream: "http://bluemsx.msxblue.com/" profiled_date: "2026-08-12" source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/metadata/conf.mk" + pattern: '^metadata_version\s*=\s*(\S+)' display_name: "MSX/ColecoVision (MSX.emu)" mode: standalone cores: diff --git a/emulators/mu.yml b/emulators/mu.yml index ffb586708..688d29b71 100644 --- a/emulators/mu.yml +++ b/emulators/mu.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/meepingsnesroms/Mu" profiled_date: "2026-03-24" source_commit: "afaeb157b8ba38a4a9bdf426ba663f7efb2cc6f8" core_version: "v1.3.3" +version_basis: + kind: file + path: "libretroBuildSystem/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Palm OS (Mu)" cores: [mu] systems: [palm-os] diff --git a/emulators/mupen64plus-ae.yml b/emulators/mupen64plus-ae.yml index 7ec92b775..132c3405c 100644 --- a/emulators/mupen64plus-ae.yml +++ b/emulators/mupen64plus-ae.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/mupen64plus-ae/mupen64plus-ae" profiled_date: "2026-08-12" source_commit: "33bf7021549d7873e976884370fbd1a8e7333bc7" core_version: "3.0.249 (beta)" +version_basis: + kind: file + path: "build_common/version_common.gradle" + pattern: 'versionName\s*=\s*"([^"]+)"' display_name: "Nintendo - Nintendo 64 (Mupen64Plus AE)" cores: - mupen64plus-ae diff --git a/emulators/mupen64plus-libretro.yml b/emulators/mupen64plus-libretro.yml index 7d334447c..f27adfa16 100644 --- a/emulators/mupen64plus-libretro.yml +++ b/emulators/mupen64plus-libretro.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/libretro/mupen64plus-libretro" profiled_date: "2026-10-22" source_commit: "ab8134ac90a567581df6de4fc427dd67bfad1b17" core_version: "2.5" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Nintendo - Nintendo 64 (Mupen64Plus 2019)" cores: - "mupen64plus_32b" diff --git a/emulators/mupen64plus.yml b/emulators/mupen64plus.yml index cded5323f..280ae6ec6 100644 --- a/emulators/mupen64plus.yml +++ b/emulators/mupen64plus.yml @@ -8,6 +8,11 @@ source_commit: "c8ac4862a019d7885b24927d9b4db5dd3e42a528" upstream_commit: "6dca4c15370ac3e2171ce7b31426695f8f39b460" upstream_frozen: "AmberELEC builds the core at this revision with the front end at source_commit. Later core commits are not part of that build." core_version: "2.6.0" +version_basis: + kind: file + path: "src/version.h" + pattern: '#define\s+CONSOLE_UI_VERSION\s+0x0?((?<=0)[0-9]|[1-9][0-9])0?((?<=0)[0-9]|[1-9][0-9])0?((?<=0)[0-9]|[1-9][0-9])\b' + format: "{1}.{2}.{3}" display_name: "Nintendo - Nintendo 64 (Mupen64Plus)" cores: - "mupen64plus" diff --git a/emulators/mupen64plus_next.yml b/emulators/mupen64plus_next.yml index 0a6980a93..60b24e922 100644 --- a/emulators/mupen64plus_next.yml +++ b/emulators/mupen64plus_next.yml @@ -7,6 +7,11 @@ profiled_date: "2026-03-24" source_commit: "15bada85906593376e8fd697f1b0b3af3a20f512" upstream_commit: "3be6336a1de6f32ccc4f57bf80c988163fe6bf7a" core_version: "2.6.0" +version_basis: + kind: file + path: "mupen64plus-core/src/main/version.h" + pattern: '#define\s+MUPEN_CORE_VERSION\s+0x0?((?<=0)[0-9]|[1-9][0-9])0?((?<=0)[0-9]|[1-9][0-9])0?((?<=0)[0-9]|[1-9][0-9])\b' + format: "{1}.{2}.{3}" display_name: "Nintendo - Nintendo 64 (Mupen64Plus-Next)" systems: [nintendo-64, nintendo-64dd] cores: [mupen64plus_next, mupen64plus_next_develop, mupen64plus_next_gles3, mupen64plus_next_gles2, mupen64plus-next, mupen64plus_nx, "mupen64plus_next_alt"] diff --git a/emulators/mupen64plus_next_develop.yml b/emulators/mupen64plus_next_develop.yml index a4f9476c9..f59ca7cac 100644 --- a/emulators/mupen64plus_next_develop.yml +++ b/emulators/mupen64plus_next_develop.yml @@ -2,7 +2,10 @@ emulator: "Mupen64Plus-Next Develop" type: alias alias_of: "mupen64plus_next" profiled_date: "2026-03-24" -core_version: "2.8" +core_version: "2.6.0" +version_basis: + kind: alias + of: "mupen64plus_next" display_name: "Nintendo - Nintendo 64 (Mupen64Plus-Next Develop)" cores: - mupen64plus_next_develop diff --git a/emulators/mupen64plus_next_gles2.yml b/emulators/mupen64plus_next_gles2.yml index 29d872373..01165cb68 100644 --- a/emulators/mupen64plus_next_gles2.yml +++ b/emulators/mupen64plus_next_gles2.yml @@ -2,7 +2,10 @@ emulator: "Mupen64Plus-Next GLES2" type: alias alias_of: "mupen64plus_next" profiled_date: "2026-03-24" -core_version: "2.8" +core_version: "2.6.0" +version_basis: + kind: alias + of: "mupen64plus_next" display_name: "Nintendo - Nintendo 64 (Mupen64Plus-Next GLES2)" cores: - mupen64plus_next_gles2 diff --git a/emulators/mupen64plus_next_gles3.yml b/emulators/mupen64plus_next_gles3.yml index 661f1ddf7..e80f488e2 100644 --- a/emulators/mupen64plus_next_gles3.yml +++ b/emulators/mupen64plus_next_gles3.yml @@ -2,7 +2,10 @@ emulator: "Mupen64Plus-Next GLES3" type: alias alias_of: "mupen64plus_next" profiled_date: "2026-03-24" -core_version: "2.8" +core_version: "2.6.0" +version_basis: + kind: alias + of: "mupen64plus_next" display_name: "Nintendo - Nintendo 64 (Mupen64Plus-Next GLES3)" cores: - mupen64plus_next_gles3 diff --git a/emulators/my-boy.yml b/emulators/my-boy.yml index 119663e3c..366c23473 100644 --- a/emulators/my-boy.yml +++ b/emulators/my-boy.yml @@ -10,6 +10,10 @@ version_source: author: "Pixel Respawn LLC" profiled_date: "2026-10-20" core_version: "2.0.3" +version_basis: + kind: package + url: "https://play.google.com/store/apps/details?id=com.fastemulator.gba" + artifact: "com.fastemulator.gba APK versionName (versionCode 90053)" display_name: "Nintendo - Game Boy Advance (My Boy!)" mode: standalone cores: diff --git a/emulators/my-oldboy.yml b/emulators/my-oldboy.yml index b49d67645..6754571be 100644 --- a/emulators/my-oldboy.yml +++ b/emulators/my-oldboy.yml @@ -10,6 +10,10 @@ version_source: author: "Pixel Respawn LLC" profiled_date: "2026-10-20" core_version: "2.0.0" +version_basis: + kind: package + url: "https://play.google.com/store/apps/details?id=com.fastemulator.gbc" + artifact: "com.fastemulator.gbc APK versionName (versionCode 90022)" display_name: "Nintendo - Game Boy / Game Boy Color (My OldBoy!)" mode: standalone cores: diff --git a/emulators/nanoboyadvance.yml b/emulators/nanoboyadvance.yml index 92546cc99..bbd61b392 100644 --- a/emulators/nanoboyadvance.yml +++ b/emulators/nanoboyadvance.yml @@ -5,7 +5,11 @@ source: "https://github.com/nba-emu/NanoBoyAdvance" profiled_date: "2026-10-17" source_commit: "3bb6f478f977dbfd3106508536e5fbce90d1898b" pin_frozen: "ROCKNIX 20261001 builds this revision of the SDL2 frontend (v1.6 plus four commits). Later upstream work is not part of that build." -core_version: "1.6" +core_version: "v1.6-4-g3bb6f47" +version_basis: + kind: tag + tag: "v1.6" + distance: 4 display_name: "Nintendo - Game Boy Advance (NanoBoyAdvance)" cores: - "nanoboyadvance" diff --git a/emulators/native32emu.yml b/emulators/native32emu.yml index 3e56eafdd..4bd95294a 100644 --- a/emulators/native32emu.yml +++ b/emulators/native32emu.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/AloysHF/Native32Emu" profiled_date: "2026-10-26" source_commit: "059fa33c658caa4dbbad140ebf2af1197f9dd778" core_version: "1.4.0" +version_basis: + kind: file + path: "Cargo.toml" + pattern: 'version\s+=\s+"([^"]+)' display_name: "Sunplus - Native32 (Native32Emu)" cores: - native32emu diff --git a/emulators/nekop2.yml b/emulators/nekop2.yml index 4f7ed432b..2c913ced7 100644 --- a/emulators/nekop2.yml +++ b/emulators/nekop2.yml @@ -6,6 +6,10 @@ upstream: "https://np2.yui.ne.jp" profiled_date: "2026-03-24" source_commit: "5fdbb2187f6b14ca7bf668dd52b36c820b989995" core_version: "0.86" +version_basis: + kind: file + path: "x11/configure.ac" + pattern: 'AC_INIT\(Xnp2,([0-9][\w.+-]*)' display_name: "NEC - PC-98 (Neko Project II)" cores: [nekop2, meowpc98] systems: [pc-98] diff --git a/emulators/neo-emu.yml b/emulators/neo-emu.yml index f56052f3f..14d2e8762 100644 --- a/emulators/neo-emu.yml +++ b/emulators/neo-emu.yml @@ -7,6 +7,10 @@ profiled_date: "2026-08-12" source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" upstream_commit: "ed06739a7202a87cd0992006628e4748aacd1ce5" core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/metadata/conf.mk" + pattern: '^metadata_version\s*=\s*(\S+)' display_name: "SNK - Neo Geo (NEO.emu)" mode: standalone cores: diff --git a/emulators/neocd.yml b/emulators/neocd.yml index 6cc0b0d0c..34b63753e 100644 --- a/emulators/neocd.yml +++ b/emulators/neocd.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/libretro/neocd_libretro" profiled_date: "2026-03-24" source_commit: "b1e04c738cb48a1dae0574b8877f6a116d270ca1" core_version: "2022" +version_basis: + kind: file + path: "src/libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "SNK - Neo Geo CD (NeoCD)" cores: - neocd diff --git a/emulators/nes-emu.yml b/emulators/nes-emu.yml index c115f4c69..e1c9688a2 100644 --- a/emulators/nes-emu.yml +++ b/emulators/nes-emu.yml @@ -8,6 +8,10 @@ source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" upstream_commit: "d339f1fa0cd8b69cc637a0de3fb3f04cb28748ea" upstream_frozen: "NES.emu's FCEUX tree is synced at this FCEUX commit of 2025-11-11. Later FCEUX commits are not in the port." core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/metadata/conf.mk" + pattern: '^metadata_version\s*=\s*(\S+)' display_name: "Nintendo - NES / Famicom (NES.emu)" mode: standalone cores: diff --git a/emulators/nes.yml b/emulators/nes.yml index 0df696d2a..63a1d38cb 100644 --- a/emulators/nes.yml +++ b/emulators/nes.yml @@ -6,6 +6,10 @@ upstream: "https://git.9front.org/plan9front/plan9front (sys/src/games/nes/)" profiled_date: "2026-03-24" source_commit: "68dfadea5889da5da7c7e171823c9b3ab24fc892" core_version: "1.0" +version_basis: + kind: file + path: "nes.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "Nintendo - NES / Famicom (nes)" cores: [nes] systems: [nintendo-nes] diff --git a/emulators/nesoid.yml b/emulators/nesoid.yml index e70e17549..73c02e044 100644 --- a/emulators/nesoid.yml +++ b/emulators/nesoid.yml @@ -6,7 +6,11 @@ upstream: "https://sourceforge.net/p/nesoid/code" author: "Yongzh (androidemu.com)" profiled_date: "2026-08-12" source_commit: "b2ff53fefa56a668aad4a579af85adc672d7a791" -core_version: "2.5-4" +core_version: "2.5" +version_basis: + kind: file + path: "app/build.gradle" + pattern: 'versionName\s+"([^"]+)"' display_name: "Nintendo - NES / Famicom (Nesoid)" mode: standalone cores: diff --git a/emulators/nestopia.yml b/emulators/nestopia.yml index 088e6b326..10a0520ad 100644 --- a/emulators/nestopia.yml +++ b/emulators/nestopia.yml @@ -7,7 +7,11 @@ logo: "https://raw.githubusercontent.com/0ldsk00l/nestopia/master/icons/svg/nest profiled_date: "2026-03-24" source_commit: "2110d21b7174455ec98948bb474147dea0e3cad0" upstream_commit: "b3adbeb42482e979ab99e16bcd9a22480f13479f" -core_version: "1.53.1" +core_version: "2.0.0" +version_basis: + kind: file + path: "libretro/libretro.cpp" + pattern: '#define\s+NST_VERSION\s+"([^"]+)"' display_name: "Nintendo - NES / Famicom (Nestopia)" cores: [nestopia] systems: [nintendo-nes, nintendo-fds] diff --git a/emulators/nethersx2-turnip-classic.yml b/emulators/nethersx2-turnip-classic.yml index be8691b44..ee33915d6 100644 --- a/emulators/nethersx2-turnip-classic.yml +++ b/emulators/nethersx2-turnip-classic.yml @@ -10,6 +10,11 @@ pin_frozen: "the classic build is this revision. v0.7 ships a newer shim, and it source_commit: "8e17e584884e19b0a912f1988730d576d6d5aa84" upstream_commit: "1d1f795dfc70e38da67724c7298779260f513889" core_version: "2.2n-3668-Turnip-v0.7" +version_basis: + kind: package + url: "https://github.com/nckstwrt/NetherSX2-Turnip/releases/download/v0.7/NetherSX2-Classic-v2.2n-3668-Turnip-v0.7.apk" + pattern: 'NetherSX2-Classic-v(.+)\.apk' + artifact: "NetherSX2-Classic-v2.2n-3668-Turnip-v0.7.apk" display_name: "Sony - PlayStation 2 (NetherSX2-Turnip Classic)" mode: standalone cores: diff --git a/emulators/nethersx2-turnip.yml b/emulators/nethersx2-turnip.yml index 8762aed6c..5f71386a0 100644 --- a/emulators/nethersx2-turnip.yml +++ b/emulators/nethersx2-turnip.yml @@ -8,7 +8,11 @@ author: "nckstwrt" profiled_date: "2026-08-12" source_commit: "3b7cf800ccac4ab5af768aee24b04363bedeb711" upstream_commit: "1d1f795dfc70e38da67724c7298779260f513889" -core_version: "2.2n-4248-Turnip-v0.7" +core_version: "v0.7" +version_basis: + kind: tag + tag: "v0.7" + distance: 0 display_name: "Sony - PlayStation 2 (NetherSX2-Turnip)" mode: standalone cores: diff --git a/emulators/nethersx2.yml b/emulators/nethersx2.yml index 1d063c154..b4398c0bf 100644 --- a/emulators/nethersx2.yml +++ b/emulators/nethersx2.yml @@ -9,6 +9,11 @@ profiled_date: "2026-10-27" source_commit: "f5f89b3b76e89a8f684da91cf5ad6e542825c0cb" upstream_commit: "1d1f795dfc70e38da67724c7298779260f513889" core_version: "2.2n-4248" +version_basis: + kind: package + url: "https://github.com/Trixarian/NetherSX2-patch/releases/download/2.2n/NetherSX2-v2.2n-4248.apk" + pattern: 'NetherSX2-v([0-9.]+[a-z]?-[0-9]+)\.apk' + artifact: "NetherSX2-v2.2n-4248.apk" display_name: "Sony - PlayStation 2 (NetherSX2)" mode: standalone cores: diff --git a/emulators/ngp-emu.yml b/emulators/ngp-emu.yml index 9da8dafdb..32ad37027 100644 --- a/emulators/ngp-emu.yml +++ b/emulators/ngp-emu.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-08-12" source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/metadata/conf.mk" + pattern: '^metadata_version\s*=\s*(\S+)' display_name: "SNK - Neo Geo Pocket / Color (NGP.emu)" mode: standalone cores: diff --git a/emulators/nicaiemu.yml b/emulators/nicaiemu.yml index dbb585e0a..0ff35ac53 100644 --- a/emulators/nicaiemu.yml +++ b/emulators/nicaiemu.yml @@ -7,6 +7,10 @@ profiled_date: "2026-10-21" source_commit: "4c9b73f7213b1537d2361a8b1d438857bdcdc798" pin_frozen: "the nicaiemu core is this revision, the last one whose .gitlab-ci.yml sets CORENAME: nicaiemu. The next master commit, 7496d513 (PR #78, 2026-10-16), renames the project and its crates to CoolbarEmu and the buildbot recipe to CORENAME: coolbaremu, so later commits build the coolbaremu core, described by coolbaremu.yml." core_version: "0.1.0" +version_basis: + kind: file + path: "Cargo.toml" + pattern: 'version\s+=\s+"([^"]+)' display_name: "MStar - Nicai (NicaiEmu)" cores: - nicaiemu diff --git a/emulators/noods.yml b/emulators/noods.yml index 593c0294d..f97db9241 100644 --- a/emulators/noods.yml +++ b/emulators/noods.yml @@ -6,7 +6,9 @@ upstream: "https://github.com/Hydr8gon/NooDS" profiled_date: "2026-03-24" source_commit: "9a2665306927ede64f4b5c109df79f4015607dbc" upstream_commit: "4cb1439c330248b26cdf5f8dbcfa4e5ac53dcda0" -core_version: "Git" +core_version: null +version_basis: + kind: none display_name: "Nintendo - DS (NooDS)" cores: [noods] systems: [nintendo-ds, nintendo-gba] diff --git a/emulators/nosgba.yml b/emulators/nosgba.yml index d82f44116..e3d51e83d 100644 --- a/emulators/nosgba.yml +++ b/emulators/nosgba.yml @@ -8,6 +8,10 @@ version_source: pattern: 'no\$gba v(\d+(?:\.\d+)+)' profiled_date: "2026-10-24" core_version: "3.06" +version_basis: + kind: package + url: "https://problemkaputt.de/gba.htm" + artifact: "no$gba-w.zip, release v3.06 of 14 Apr 2025 on the download page" display_name: "Nintendo - GBA/DS/DSi (no$gba)" cores: - nosgba diff --git a/emulators/np2kai.yml b/emulators/np2kai.yml index 1f2214abc..2ccbae0a4 100644 --- a/emulators/np2kai.yml +++ b/emulators/np2kai.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-24" source_commit: "1ea561cd7fd62b33f4e7b3f1c2e30fc3e6089f28" upstream_commit: "5d47f3a04b0b8ea78f625eeec354ac132c80df06" core_version: "0.86" +version_basis: + kind: file + path: "np2ver.h" + pattern: '#define\s+NP2VER_CORE\s+"([0-9][0-9.]*)"' display_name: "NEC - PC-98 (Neko Project II Kai)" cores: [np2kai] systems: [pc-98] diff --git a/emulators/np2pi.yml b/emulators/np2pi.yml index 66d29cefa..a8d3b5267 100644 --- a/emulators/np2pi.yml +++ b/emulators/np2pi.yml @@ -6,6 +6,10 @@ upstream: "https://np2.yui.ne.jp" profiled_date: "2026-10-20" source_commit: "2e995768b55e97acfaac32d45fbb8351645cba62" core_version: "0.83" +version_basis: + kind: file + path: "np2ver.h" + pattern: '#define\s+NP2VER_CORE\s+"ver\.([0-9][^"]*)"' display_name: "NEC - PC-98 (np2pi)" mode: standalone cores: diff --git a/emulators/nuance.yml b/emulators/nuance.yml index a07611c3c..6d0dcdd59 100644 --- a/emulators/nuance.yml +++ b/emulators/nuance.yml @@ -7,6 +7,10 @@ profiled_date: "2026-09-03" source_commit: "daf3ca642756a559ecce91e10da0e73cbad180ff" upstream_commit: "daf3ca642756a559ecce91e10da0e73cbad180ff" core_version: "0.6.7" +version_basis: + kind: file + path: "src/libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "VM Labs - NUON (Nuance)" cores: [nuance] systems: [vm-labs-nuon] diff --git a/emulators/numero.yml b/emulators/numero.yml index 07621dbef..41727febb 100644 --- a/emulators/numero.yml +++ b/emulators/numero.yml @@ -5,7 +5,11 @@ source: "https://github.com/nbarkhina/numero" upstream: "https://github.com/sputt/wabbitemu" profiled_date: "2026-03-24" source_commit: "c0b07a39782feafebcde0c8ccfa91fc92732c999" -core_version: "v1.0" +core_version: "1.1" +version_basis: + kind: file + path: "libnumero/libretro/libretronew.cpp" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "Texas Instruments TI-83 (Numero)" cores: - numero diff --git a/emulators/nxengine.yml b/emulators/nxengine.yml index c47f4e0b0..661a3e0de 100644 --- a/emulators/nxengine.yml +++ b/emulators/nxengine.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/Rox64/NXEngine" profiled_date: "2026-03-24" source_commit: "fd1c0686f8b4c0aea9b5addbc077e3ad7da23bb7" core_version: "1.0.0.6" +version_basis: + kind: file + path: "nxengine/libretro/libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Cave Story (NXEngine)" cores: [nxengine, nx] systems: [cave-story] diff --git a/emulators/o2em.yml b/emulators/o2em.yml index 5bc7f467c..586ec8cb9 100644 --- a/emulators/o2em.yml +++ b/emulators/o2em.yml @@ -8,6 +8,10 @@ upstream: "https://sourceforge.net/projects/o2em/" profiled_date: "2026-03-24" source_commit: "679d6fec04963f6e70a7ec217e3d0ebb1fe472fc" core_version: "1.18" +version_basis: + kind: file + path: "libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Magnavox - Odyssey2 / Philips Videopac+ (O2EM)" systems: - odyssey2 diff --git a/emulators/oberon.yml b/emulators/oberon.yml index 20c000268..c8ca46f1c 100644 --- a/emulators/oberon.yml +++ b/emulators/oberon.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/oberon-risc-emu" upstream: "https://github.com/pdewacht/oberon-risc-emu" profiled_date: "2026-03-24" source_commit: "5be71d885b87b7cd7c635bf330764fcc4f3905fe" -core_version: "2026-08-23" +core_version: "v2016.1-56-g5be71d8" +version_basis: + kind: tag + tag: "v2016.1" + distance: 56 display_name: "Oberon RISC Emulator" cores: - oberon diff --git a/emulators/omicron.yml b/emulators/omicron.yml index 356c33709..1f5e68fbf 100644 --- a/emulators/omicron.yml +++ b/emulators/omicron.yml @@ -8,6 +8,10 @@ profiled_date: "2026-09-17" source_commit: "0181fbad079addb1fca895325c711f8f91397be4" upstream_commit: "aaaa2f1a98b88a6b1e6102417317ced206887076" core_version: "v1" +version_basis: + kind: file + path: "libretro/LibretroOmicronCore/omicron_libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Omicron" cores: - omicron diff --git a/emulators/onscripter.yml b/emulators/onscripter.yml index f024eb12d..937176f9d 100644 --- a/emulators/onscripter.yml +++ b/emulators/onscripter.yml @@ -5,7 +5,11 @@ source: "https://github.com/iyzsong/onscripter-libretro" upstream: "https://github.com/ogapee/onscripter" profiled_date: "2026-03-24" source_commit: "ec4ff1842d498faaa844d570becf561d088deea0" -core_version: "0.3" +core_version: "v0.3" +version_basis: + kind: tag + tag: "v0.3" + distance: 0 display_name: "ONScripter" cores: - onscripter diff --git a/emulators/onsyuri.yml b/emulators/onsyuri.yml index 773f044ac..f9cb829f1 100644 --- a/emulators/onsyuri.yml +++ b/emulators/onsyuri.yml @@ -5,7 +5,11 @@ source: "https://github.com/YuriSizuku/OnscripterYuri" upstream: "https://github.com/YuriSizuku/OnscripterYuri" profiled_date: "2026-03-24" source_commit: "08f744b31cc1907b66a15f0402e62321a131ed81" -core_version: "0.7.4+2" +core_version: "v0.7.7beta" +version_basis: + kind: tag + tag: "v0.7.7beta" + distance: 0 display_name: "ONScripter Yuri" cores: - onsyuri diff --git a/emulators/openbor.yml b/emulators/openbor.yml index 154161259..5cc4787a5 100644 --- a/emulators/openbor.yml +++ b/emulators/openbor.yml @@ -5,7 +5,12 @@ source: "https://github.com/DCurrent/openbor" upstream: "https://github.com/DCurrent/openbor" profiled_date: "2026-08-12" source_commit: "65a7f0b41aee87fe4084e538634b4ed73236f871" -core_version: "4.0 Build 7949" +core_version: "4.0" +version_basis: + kind: file + path: "engine/version.sh" + pattern: '^VERSION_MAJOR=(\d+)\s*\nVERSION_MINOR=(\d+)' + format: "{1}.{2}" display_name: "OpenBOR Game Engine" cores: - openbor diff --git a/emulators/opengoal.yml b/emulators/opengoal.yml index a05787a7c..47eceb1ab 100644 --- a/emulators/opengoal.yml +++ b/emulators/opengoal.yml @@ -7,6 +7,10 @@ source_commit: "6445b4a50a7540df512e3c82c62216521421410c" pin_frozen: "RetroBat, the only platform that ships it, installs this release: the gk.exe of its opengoal.7z package (10 October 2026) is byte identical to the one in opengoal-windows-v0.3.8.zip. Later releases are not part of that package." profiled_date: "2026-10-20" core_version: "v0.3.8" +version_basis: + kind: tag + tag: "v0.3.8" + distance: 0 display_name: "Jak and Daxter (OpenGOAL)" cores: [opengoal] systems: [opengoal] diff --git a/emulators/openjazz.yml b/emulators/openjazz.yml index aa7e48aa3..67cab5426 100644 --- a/emulators/openjazz.yml +++ b/emulators/openjazz.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/AlisterT/openjazz" profiled_date: "2026-10-04" source_commit: "a1626f4edd4a7af72c54103021790c56d8ecfced" core_version: "20260301" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: '^project\(OpenJazz\s+VERSION\s+(\S+)' display_name: "Jazz Jackrabbit (OpenJazz)" cores: ["OpenJazz"] systems: [jazz-jackrabbit] diff --git a/emulators/openjk.yml b/emulators/openjk.yml index c04ed1abe..0625ac61d 100644 --- a/emulators/openjk.yml +++ b/emulators/openjk.yml @@ -5,6 +5,12 @@ source: "https://github.com/JACoders/OpenJK" upstream: "https://github.com/JACoders/OpenJK" profiled_date: "2026-10-04" source_commit: "260c59c2907187af555a676fe0cc798893bf7757" +core_version: "v0.0.0-951-g260c59c" +version_basis: + kind: tag + match: "v*" + tag: "v0.0.0" + distance: 951 display_name: "OpenJK" cores: [openjk] systems: [jediacademy, jediknight2] diff --git a/emulators/openjkdf2.yml b/emulators/openjkdf2.yml index a31e42d78..6b741fb4f 100644 --- a/emulators/openjkdf2.yml +++ b/emulators/openjkdf2.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/shinyquagsire23/OpenJKDF2" profiled_date: "2026-10-04" source_commit: "798f930402525a23b94671d85b97b00390342fa0" core_version: "0.9.9.0" +version_basis: + kind: file + path: "cmake_modules/version.cmake" + pattern: 'set\(OPENJKDF2_PROJECT_VERSION\s+([0-9.]+)\)' display_name: "OpenJKDF2" cores: [] systems: diff --git a/emulators/openlara.yml b/emulators/openlara.yml index ca595a41e..9c24c8a52 100644 --- a/emulators/openlara.yml +++ b/emulators/openlara.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-24" source_commit: "e4ce52edec5a9a6ad22b69d08c687bf070e68876" upstream_commit: "3b268ca4bf986c380f44a26ffd9218bf6d376249" core_version: "v1" +version_basis: + kind: file + path: "src/platform/libretro/main.cpp" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "Tomb Raider (OpenLara)" cores: [openlara] systems: [tomb-raider] diff --git a/emulators/openmohaa.yml b/emulators/openmohaa.yml index cd6b87e27..9cf083712 100644 --- a/emulators/openmohaa.yml +++ b/emulators/openmohaa.yml @@ -6,6 +6,11 @@ upstream: "https://github.com/openmoh/openmohaa" profiled_date: "2026-10-04" source_commit: "a2f340195975f4f042e28a60b62561dd9a0b2700" upstream_commit: "a2f340195975f4f042e28a60b62561dd9a0b2700" +core_version: "0.83.0" +version_basis: + kind: file + path: "cmake/identity.cmake" + pattern: 'set\(PROJECT_VERSION\s+([0-9][^)\s]*)\)' display_name: "OpenMoHAA" cores: [] systems: [mohaa, mohaa-spearhead, mohaa-breakthrough] diff --git a/emulators/openmsx.yml b/emulators/openmsx.yml index 26084c8e8..e8cb758fa 100644 --- a/emulators/openmsx.yml +++ b/emulators/openmsx.yml @@ -4,7 +4,11 @@ source: "https://github.com/openMSX/openMSX" upstream: "https://github.com/openMSX/openMSX" profiled_date: "2026-03-26" source_commit: "a557de7b37bc48420b63ec10e7ede953babad4f9" -core_version: "21.0" +core_version: "RELEASE_22_0_RC2" +version_basis: + kind: tag + tag: "RELEASE_22_0_RC2" + distance: 0 display_name: "MSX / ColecoVision / Spectravideo (openMSX)" cores: - openmsx diff --git a/emulators/openttd.yml b/emulators/openttd.yml index 6a1728cf2..e5b1b7dd2 100644 --- a/emulators/openttd.yml +++ b/emulators/openttd.yml @@ -5,6 +5,10 @@ source: "https://github.com/OpenTTD/OpenTTD" profiled_date: "2026-10-20" source_commit: "61342620bc4c0971b28b3578379b53d04d2f11f1" core_version: "14.1" +version_basis: + kind: tag + tag: "14.1" + distance: 0 display_name: "Transport Tycoon Deluxe (OpenTTD)" mode: standalone cores: diff --git a/emulators/opentyrian.yml b/emulators/opentyrian.yml index afbaf09fc..2790b9f8c 100644 --- a/emulators/opentyrian.yml +++ b/emulators/opentyrian.yml @@ -6,7 +6,9 @@ upstream: "https://github.com/opentyrian/opentyrian" profiled_date: "2026-03-24" source_commit: "3e9df7a6bc486190ad5085586d0c4e9cb1baf14c" upstream_commit: "ac5d0e71f4245744350c6116ce24f10624da58f8" -core_version: "1.0.0.6" +core_version: null +version_basis: + kind: none display_name: "Tyrian (OpenTyrian)" cores: [opentyrian, tyrian] systems: [tyrian] diff --git a/emulators/opera.yml b/emulators/opera.yml index 97d570f8d..9da041b28 100644 --- a/emulators/opera.yml +++ b/emulators/opera.yml @@ -8,6 +8,10 @@ upstream: "https://sourceforge.net/projects/freedo/" profiled_date: "2026-10-18" source_commit: "370d9a25c030bb9de4aade371b31045691c40a95" core_version: "1.0.0" +version_basis: + kind: file + path: "libretro.c" + pattern: 'info_->library_version\s+=\s+"([^"]+)' display_name: "The 3DO Company - 3DO (Opera)" systems: - 3do diff --git a/emulators/oricutron.yml b/emulators/oricutron.yml index c2ed07844..28cf5119e 100644 --- a/emulators/oricutron.yml +++ b/emulators/oricutron.yml @@ -5,7 +5,12 @@ source: "https://github.com/pete-gordon/oricutron" upstream: "https://www.petergordon.org.uk/oricutron/" profiled_date: "2026-08-08" source_commit: "002279fce9fa756d1d63cdc40ae97939eb7de7ed" -core_version: "V1_2_14" +core_version: "1.2.0" +version_basis: + kind: file + path: "Makefile" + pattern: '^VERSION_MAJ\s*=\s*(\d+)\s*\nVERSION_MIN\s*=\s*(\d+)\s*\nVERSION_REV\s*=\s*(\d+)' + format: "{1}.{2}.{3}" display_name: "Tangerine - Oric (Oricutron)" cores: - oricutron diff --git a/emulators/osmose.yml b/emulators/osmose.yml index bd1164734..b10fb7273 100644 --- a/emulators/osmose.yml +++ b/emulators/osmose.yml @@ -4,7 +4,11 @@ core_classification: community_fork source: "https://github.com/RetroPie/osmose-rpi" profiled_date: "2026-10-20" source_commit: "7775add582ad2595e876ca38d4675510f2df866e" -core_version: "0.8.1+rpi20130302" +core_version: "0.8.1+rpi20121122" +version_basis: + kind: file + path: "Version.h" + pattern: '#define\s+__OSMOSE_VERSION__\s+"OsmOse\s+([^"]+)"' display_name: "Sega - Master System / Game Gear (Osmose)" mode: standalone cores: diff --git a/emulators/panda3ds.yml b/emulators/panda3ds.yml index 199756601..27295411c 100644 --- a/emulators/panda3ds.yml +++ b/emulators/panda3ds.yml @@ -6,7 +6,11 @@ source: "https://github.com/panda3ds-emu/panda3ds" upstream: "https://github.com/panda3ds-emu/panda3ds" profiled_date: "2026-03-24" source_commit: "3787358bdae41d5532ccd00c8998a527ae949949" -core_version: "Git" +core_version: "v0.8-615-g3787358" +version_basis: + kind: tag + tag: "v0.8" + distance: 615 display_name: "Nintendo - 3DS (Panda3DS)" library_name: "Panda3DS" cores: [panda3ds] diff --git a/emulators/parallel-launcher.yml b/emulators/parallel-launcher.yml index 253a54e30..1f1222cb6 100644 --- a/emulators/parallel-launcher.yml +++ b/emulators/parallel-launcher.yml @@ -6,7 +6,12 @@ upstream: "https://gitlab.com/parallel-launcher/parallel-n64" profiled_date: "2026-08-08" source_commit: "8dc2a83770c57bc00e1b1fae0aed71f2120cc875" upstream_commit: "a9028b23bd5ee8b465eefc64320fd7701f3430fa" -core_version: "v9.0-6" +core_version: "9.0.6" +version_basis: + kind: file + path: "src/core/version.cpp" + pattern: 'CurrentVersion::Application\s*=\s*\{\s*(\d+),\s*(\d+),\s*(\d+)\s*\}' + format: "{1}.{2}.{3}" display_name: "Nintendo - Nintendo 64 (Parallel Launcher)" cores: - parallel-launcher diff --git a/emulators/parallel_n64.yml b/emulators/parallel_n64.yml index 87e3e71da..d103fdc28 100644 --- a/emulators/parallel_n64.yml +++ b/emulators/parallel_n64.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/mupen64plus/mupen64plus-core" profiled_date: "2026-03-24" source_commit: "f87550d9ad70cb320870e2b5fd960235287abb89" upstream_commit: "3be6336a1de6f32ccc4f57bf80c988163fe6bf7a" -core_version: "2.0-rc2" +core_version: "1.0" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "Nintendo - Nintendo 64 (ParaLLEl N64)" systems: [nintendo-64, nintendo-64dd] cores: [parallel_n64, parallel_n64_debug, "parallel_n64_32b", "parallel-n64"] diff --git a/emulators/parallel_n64_debug.yml b/emulators/parallel_n64_debug.yml index d66ab6b2a..29fc75b63 100644 --- a/emulators/parallel_n64_debug.yml +++ b/emulators/parallel_n64_debug.yml @@ -2,7 +2,10 @@ emulator: "parallel_n64_debug" type: alias alias_of: "parallel_n64" profiled_date: "2026-03-24" -core_version: "2.0-rc2" +core_version: "1.0" +version_basis: + kind: alias + of: "parallel_n64" display_name: "Nintendo - Nintendo 64 (ParaLLEl) (Debug)" cores: - parallel_n64_debug diff --git a/emulators/pascal_pong.yml b/emulators/pascal_pong.yml index fa4865d37..de5fe2edf 100644 --- a/emulators/pascal_pong.yml +++ b/emulators/pascal_pong.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/pascal-pong-libretro" upstream: "https://github.com/libretro/pascal-pong-libretro" profiled_date: "2026-03-24" source_commit: "2a0cfd44652c0b215862de3ef56916d1384ad8a0" -core_version: "v1.0" +core_version: "1.0" +version_basis: + kind: file + path: "pong.pas" + pattern: 'LibraryVersion\s*:=\s*''([^'']+)''' display_name: "PascalPong" cores: [pascal_pong] systems: [] diff --git a/emulators/pce-emu.yml b/emulators/pce-emu.yml index cfe320bfe..08eadaab3 100644 --- a/emulators/pce-emu.yml +++ b/emulators/pce-emu.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-08-12" source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/metadata/conf.mk" + pattern: '^metadata_version\s*=\s*(\S+)' display_name: "PCE.emu" cores: ["pce-emu", "PCE.emu", "pceemu", "PCE-EMU", "com.PceEmu"] systems: [nec-pc-engine, nec-pc-engine-cd, nec-supergrafx] diff --git a/emulators/pcee2.yml b/emulators/pcee2.yml index 8e80dc812..11dea57cf 100644 --- a/emulators/pcee2.yml +++ b/emulators/pcee2.yml @@ -8,6 +8,11 @@ profiled_date: "2026-09-03" source_commit: "f52b5a6fe43278dcfc827b85b09fced5a82f863f" upstream_commit: "ab0b401f99729ef8da3009f9af28d8ee96e0e7ba" core_version: "v2.9.138" +version_basis: + kind: tag + repo: upstream + tag: "v2.9.138" + distance: 0 display_name: "Sony - PlayStation 2 (PCEE2)" cores: [pcee2] systems: [sony-playstation-2] diff --git a/emulators/pcem.yml b/emulators/pcem.yml index 98239f60b..a77666867 100644 --- a/emulators/pcem.yml +++ b/emulators/pcem.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/sarah-walker-pcem/pcem" profiled_date: "2026-03-24" source_commit: "e07923e902dcedcf65a502fb3f14e75b9ded5271" upstream_commit: "25b54e3ff1d51cbf2469b447e55bce7a589697e9" -core_version: "v11 (PCem-mooch, based on PCem v10.1)" +core_version: "v10.1" +version_basis: + kind: file + path: "configure.ac" + pattern: '^AC_INIT\(PCem,\s*([^,\s]+),' display_name: "PC (PCem)" cores: [pcem] systems: diff --git a/emulators/pcsx1.yml b/emulators/pcsx1.yml index e5fc2f300..748f9fc17 100644 --- a/emulators/pcsx1.yml +++ b/emulators/pcsx1.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-24" source_commit: "35dabb85ff3af6825820f54090d344945f65d24e" upstream_commit: "8b6c163575e6ce9a0537553e0d4ed4225315955e" core_version: "r22" +version_basis: + kind: file + path: "frontend/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Sony - PlayStation (PCSX1)" cores: [pcsx1] systems: [sony-playstation] diff --git a/emulators/pcsx2-legacy.yml b/emulators/pcsx2-legacy.yml index 737600eae..74ec65c37 100644 --- a/emulators/pcsx2-legacy.yml +++ b/emulators/pcsx2-legacy.yml @@ -6,7 +6,11 @@ source: "https://github.com/PCSX2/pcsx2" upstream: "https://github.com/PCSX2/pcsx2" profiled_date: "2026-08-08" source_commit: "aaaf29557fe63870ede815dd6d2e48a98279ca59" -core_version: "1.6.0" +core_version: "v1.6.0" +version_basis: + kind: tag + tag: "v1.6.0" + distance: 0 display_name: "Sony - PlayStation 2 (PCSX2 Legacy)" cores: - pcsx2-legacy diff --git a/emulators/pcsx2.yml b/emulators/pcsx2.yml index d428e1188..693e6f9f0 100644 --- a/emulators/pcsx2.yml +++ b/emulators/pcsx2.yml @@ -8,7 +8,11 @@ cores: - pcsx2 profiled_date: "2026-03-30" source_commit: "f0523f8acb1d3a765ee73b74cffec63093569199" -core_version: "Git" +core_version: "v2.9.146-1-gf0523f8" +version_basis: + kind: tag + tag: "v2.9.146" + distance: 1 display_name: "Sony - PlayStation 2 (PCSX2)" systems: [sony-playstation-2] diff --git a/emulators/pcsx2x6.yml b/emulators/pcsx2x6.yml index 616929928..aeb3ea2cb 100644 --- a/emulators/pcsx2x6.yml +++ b/emulators/pcsx2x6.yml @@ -8,7 +8,11 @@ profiled_date: "2026-08-08" source_commit: "583f0e90907d69bb2db670f570d0865260fcc71b" upstream_commit: "3df128d9f9cd89cfc47d08d94b3439136ba22b33" prose_written_at: "583f0e90907d69bb2db670f570d0865260fcc71b" -core_version: "v0.2.22" +core_version: "v0.2.22-2-g583f0e9" +version_basis: + kind: tag + tag: "v0.2.22" + distance: 2 display_name: "Namco - System 246 / 256 (PCSX2x6)" cores: - pcsx2x6 diff --git a/emulators/pcsx_rearmed.yml b/emulators/pcsx_rearmed.yml index 66beb94ae..b7a409479 100644 --- a/emulators/pcsx_rearmed.yml +++ b/emulators/pcsx_rearmed.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/notaz/pcsx_rearmed" profiled_date: "2026-03-25" source_commit: "c8816799b50388e61cfe237fe2cdbb7d8175f20a" upstream_commit: "8b6c163575e6ce9a0537553e0d4ed4225315955e" -core_version: "r25" +core_version: "r26" +version_basis: + kind: file + path: "frontend/libretro.c" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "Sony - PlayStation (PCSX ReARMed)" cores: [pcsx_rearmed, pcsx_rearmed_neon, pcsx_rearmed_interpreter, "pcsx_rearmed_32b"] systems: [sony-playstation] diff --git a/emulators/pcsx_rearmed_standalone.yml b/emulators/pcsx_rearmed_standalone.yml index 8924ddcfb..fc12264fc 100644 --- a/emulators/pcsx_rearmed_standalone.yml +++ b/emulators/pcsx_rearmed_standalone.yml @@ -5,6 +5,10 @@ source: "https://github.com/notaz/pcsx_rearmed" profiled_date: "2026-10-20" source_commit: "8b6c163575e6ce9a0537553e0d4ed4225315955e" core_version: "r26" +version_basis: + kind: file + path: "frontend/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Sony - PlayStation (PCSX-ReARMed standalone)" mode: standalone cores: diff --git a/emulators/pd777.yml b/emulators/pd777.yml index f71a33f65..0944cc773 100644 --- a/emulators/pd777.yml +++ b/emulators/pd777.yml @@ -5,7 +5,11 @@ source: "https://github.com/mittonk/PD777" upstream: "https://github.com/W88DodPECuThLOl/PD777" profiled_date: "2026-03-24" source_commit: "331af5f53cc0ffbab90f915681c8dfe3a4cda0a2" -core_version: "v1.0.0" +core_version: "1.01.01" +version_basis: + kind: file + path: "source/libretro/libretro.cpp" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "Epoch - Cassette Vision (PD777)" cores: - pd777 diff --git a/emulators/pdark.yml b/emulators/pdark.yml index c7ac7731b..863e27f03 100644 --- a/emulators/pdark.yml +++ b/emulators/pdark.yml @@ -6,7 +6,9 @@ upstream: "https://github.com/perfect-dark-pc-port/perfect_dark" source_branch: port source_commit: "32a1cb9f268dd3ac73016801025c6bbbfa20130f" profiled_date: "2026-10-20" -core_version: "port 2025-06-14" +core_version: null +version_basis: + kind: none display_name: "Perfect Dark (PC port)" cores: [pdark] systems: [pdark] diff --git a/emulators/phoenix.yml b/emulators/phoenix.yml index 0239cb85c..e56e2dd41 100644 --- a/emulators/phoenix.yml +++ b/emulators/phoenix.yml @@ -5,6 +5,10 @@ source: "http://www.arts-union.ru" upstream: "http://www.arts-union.ru" profiled_date: "2026-10-20" core_version: "2.8.JAG" +version_basis: + kind: package + url: "https://www.retrobat.ovh/repo/win64/stable/emulators/phoenix.7z" + artifact: "phoenix.7z, PhoenixEmuProject.exe version string" display_name: "3DO, Atari Jaguar (Phoenix)" mode: standalone cores: diff --git a/emulators/picodrive.yml b/emulators/picodrive.yml index 71ec0610f..027f87c02 100644 --- a/emulators/picodrive.yml +++ b/emulators/picodrive.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/irixxxx/picodrive" profiled_date: "2026-03-24" source_commit: "1890c2932234c9d30f4cd3851d02228baae8f09e" upstream_commit: "5f9e79f2177443939f21ab965b1c294edbef514c" -core_version: "1.99" +core_version: "2.05" +version_basis: + kind: file + path: "platform/common/version.h" + pattern: '#define\s+VERSION\s+"([^"]+)"' display_name: "Sega - MS/GG/MD/CD/32X (PicoDrive)" cores: [picodrive] systems: diff --git a/emulators/piece.yml b/emulators/piece.yml index 4bdeacfdd..84b8feb5e 100644 --- a/emulators/piece.yml +++ b/emulators/piece.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/autch/piece-emu" profiled_date: "2026-09-17" source_commit: "08ec4b45176e8df0d6d6f67e56b87e847cd64a65" core_version: "0.1" +version_basis: + kind: file + path: "src/libretro/piece_libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Aquaplus - P/ECE (piece-emu)" cores: - piece diff --git a/emulators/piemu.yml b/emulators/piemu.yml index f5bb484a5..f0b5bdef3 100644 --- a/emulators/piemu.yml +++ b/emulators/piemu.yml @@ -7,7 +7,11 @@ profiled_date: "2026-10-22" source_commit: "0785214f13746bdfd709b1909f007e213b470ba1" upstream_commit: "23208626e16e53b73fd21a2fbd0c429338625dc4" pin_frozen: "AmberELEC, the only platform that ships it, builds this revision (AmberELEC packages/games/emulators/piemu/package.mk:5). Later commits are not part of that build." -core_version: "git" +core_version: "20030430" +version_basis: + kind: file + path: "app.h" + pattern: '#define\s+VERSION\s+"([^"]+)"' display_name: "Aquaplus - P/ECE (P/EMU/SDL)" cores: - "piemu" diff --git a/emulators/pisnes.yml b/emulators/pisnes.yml index 68a7bd6fd..69f70ecd4 100644 --- a/emulators/pisnes.yml +++ b/emulators/pisnes.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/pisnes/" profiled_date: "2026-10-20" source_commit: "a5b427f255f922cfa65e29c4285b3d565a4c9044" core_version: "1.39" +version_basis: + kind: file + path: "snes9x.h" + pattern: '#define\s+VERSION\s+"([^"]+)"' display_name: "Nintendo - SNES (PiSNES)" mode: standalone cores: diff --git a/emulators/pizza-boy-gba.yml b/emulators/pizza-boy-gba.yml index daf89b967..5c61dd508 100644 --- a/emulators/pizza-boy-gba.yml +++ b/emulators/pizza-boy-gba.yml @@ -10,6 +10,10 @@ version_source: author: "Pizza Emulators" profiled_date: "2026-10-24" core_version: "2.8.13" +version_basis: + kind: package + url: "https://play.google.com/store/apps/details?id=it.dbtecno.pizzaboygbapro" + artifact: "it.dbtecno.pizzaboygbapro APK versionName (versionCode 343)" display_name: "Nintendo - Game Boy Advance (Pizza Boy GBA)" mode: standalone cores: diff --git a/emulators/pizza-boy-gbc.yml b/emulators/pizza-boy-gbc.yml index 566895fda..5c74ba3e5 100644 --- a/emulators/pizza-boy-gbc.yml +++ b/emulators/pizza-boy-gbc.yml @@ -10,6 +10,10 @@ version_source: author: "Pizza Emulators" profiled_date: "2026-10-24" core_version: "6.0.6" +version_basis: + kind: package + url: "https://play.google.com/store/apps/details?id=it.dbtecno.pizzaboypro" + artifact: "it.dbtecno.pizzaboypro APK versionName (versionCode 231)" display_name: "Nintendo - Game Boy / Color (Pizza Boy GBC)" mode: standalone cores: diff --git a/emulators/pizza-boy-sc.yml b/emulators/pizza-boy-sc.yml index 2658f40ee..b1c7d787b 100644 --- a/emulators/pizza-boy-sc.yml +++ b/emulators/pizza-boy-sc.yml @@ -10,6 +10,10 @@ version_source: author: "Pizza Emulators" profiled_date: "2026-10-20" core_version: "1.2.14" +version_basis: + kind: package + url: "https://play.google.com/store/apps/details?id=it.dbtecno.pizzaboyscbasic" + artifact: "it.dbtecno.pizzaboyscbasic XAPK versionName (versionCode 43)" display_name: "Sega - MS/GG/MD/CD (Pizza Boy SC)" mode: standalone cores: diff --git a/emulators/plastic.yml b/emulators/plastic.yml index ba45df4ee..86256d9a9 100644 --- a/emulators/plastic.yml +++ b/emulators/plastic.yml @@ -5,7 +5,11 @@ source: "https://github.com/Amjad50/plastic" upstream: "https://github.com/Amjad50/plastic" profiled_date: "2026-08-12" source_commit: "74152adb3acd890d3abee2ff5906408f26a199e2" -core_version: "0.3.5" +core_version: "v0.3.5" +version_basis: + kind: tag + tag: "v0.3.5" + distance: 0 display_name: "Nintendo - NES / Famicom (Plastic)" cores: - plastic diff --git a/emulators/play.yml b/emulators/play.yml index b58a35f05..a887597e9 100644 --- a/emulators/play.yml +++ b/emulators/play.yml @@ -5,7 +5,11 @@ source: "https://github.com/jpd002/Play-" upstream: "https://github.com/jpd002/Play-" profiled_date: "2026-03-24" source_commit: "1f27232772e484bfb79364b751b84f41f4c87481" -core_version: "Git" +core_version: "0.77-17-g1f27232" +version_basis: + kind: tag + tag: "0.77" + distance: 17 display_name: "Sony - PlayStation 2 (Play!)" cores: - play diff --git a/emulators/playdiaemu.yml b/emulators/playdiaemu.yml index f2fd55d5a..bb7362410 100644 --- a/emulators/playdiaemu.yml +++ b/emulators/playdiaemu.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/AloysHF/PlaydiaEmu" profiled_date: "2026-10-23" source_commit: "b1b990e7f28d6baa58d5fcde9faa155990ee8f3f" core_version: "0.1.0" +version_basis: + kind: file + path: "Cargo.toml" + pattern: 'version\s+=\s+"([^"]+)' display_name: "Bandai - Playdia (PlaydiaEmu)" cores: - playdiaemu diff --git a/emulators/pocketcdg.yml b/emulators/pocketcdg.yml index 8d776c940..4fb11a200 100644 --- a/emulators/pocketcdg.yml +++ b/emulators/pocketcdg.yml @@ -5,7 +5,9 @@ source: "https://github.com/libretro/libretro-pocketcdg" upstream: "https://github.com/libretro/libretro-pocketcdg" profiled_date: "2026-03-24" source_commit: "c6fc08d942753342686cb9494e1d285a14c1893c" -core_version: "Git" +core_version: null +version_basis: + kind: none display_name: "PocketCDG" cores: [pocketcdg] systems: [] diff --git a/emulators/pokemini.yml b/emulators/pokemini.yml index 2d4aa7f5c..aad109124 100644 --- a/emulators/pokemini.yml +++ b/emulators/pokemini.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/pokemini/" profiled_date: "2026-03-24" source_commit: "132111b76343559860532a1ccc094f93f1ed5650" core_version: "v0.60" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Nintendo - Pokemon Mini (PokeMini)" cores: - pokemini diff --git a/emulators/pokketstation.yml b/emulators/pokketstation.yml index 9a19ee95e..2560c0ff4 100644 --- a/emulators/pokketstation.yml +++ b/emulators/pokketstation.yml @@ -5,7 +5,11 @@ source: "https://github.com/mentalfoundry/Pokket" upstream: "https://github.com/mentalfoundry/Pokket" profiled_date: "2026-10-17" source_commit: "37c022ce46eb578de5b57d7b488ffda9e3b7d9f1" -core_version: "v1.23" +core_version: "1.23" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'project\(pokket\s+VERSION\s+([0-9][\w.+-]*)' display_name: "Sony - PocketStation (pokketstation)" cores: ["pokketstation", "pokket"] systems: [sony-pocketstation] diff --git a/emulators/pom2.yml b/emulators/pom2.yml index 6c4306833..fa75430d7 100644 --- a/emulators/pom2.yml +++ b/emulators/pom2.yml @@ -5,7 +5,11 @@ source: "https://github.com/habib256/pom2" upstream: "https://github.com/habib256/pom2" profiled_date: "2026-10-23" source_commit: "dbf7673d0ca938884419335f3d88e9029c15494f" -core_version: "v0.9.9" +core_version: "0.9.9" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'project\(pom2_imgui\s+VERSION\s+([0-9][\w.+-]*)' display_name: "Apple - Apple II (POM2)" cores: - pom2 diff --git a/emulators/potator.yml b/emulators/potator.yml index f747a2b56..ed0b024e1 100644 --- a/emulators/potator.yml +++ b/emulators/potator.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/alekmaul/potator" profiled_date: "2026-03-24" source_commit: "227c5f6f3ce74d32e9002ce24c1420288559a860" core_version: "1.0.5" +version_basis: + kind: file + path: "platform/libretro/libretro.c" + pattern: 'info->library_version\s*=\s*"([^" ]+)' display_name: "Watara - Supervision (Potator)" cores: - potator diff --git a/emulators/ppsspp-1.5.4.yml b/emulators/ppsspp-1.5.4.yml index 206016ae3..1ba7ad930 100644 --- a/emulators/ppsspp-1.5.4.yml +++ b/emulators/ppsspp-1.5.4.yml @@ -6,6 +6,10 @@ profiled_date: "2026-10-20" source_commit: "a1e74d0d4f89ba3fa2d4fe64bac7a0fa16fc146f" pin_frozen: "RetroPie, the only platform that ships it, builds the v1.5.4 tag at this commit (RetroPie scriptmodules/emulators/ppsspp-1.5.4.sh:16). Later releases are packaged separately as ppsspp." core_version: "v1.5.4" +version_basis: + kind: tag + tag: "v1.5.4" + distance: 0 display_name: "Sony - PlayStation Portable (PPSSPP 1.5.4)" mode: standalone cores: diff --git a/emulators/ppsspp.yml b/emulators/ppsspp.yml index d2e07ba3b..4ee72cf14 100644 --- a/emulators/ppsspp.yml +++ b/emulators/ppsspp.yml @@ -4,7 +4,11 @@ core_classification: official_port source: "https://github.com/hrydgard/ppsspp" profiled_date: "2026-10-21" source_commit: "43a69b1c84dfe29e82b46bd3797a1106cbd65c5b" -core_version: "Git" +core_version: "v1.20.4-3958-g43a69b1" +version_basis: + kind: tag + tag: "v1.20.4" + distance: 3958 display_name: "Sony - PlayStation Portable (PPSSPP)" cores: - ppsspp diff --git a/emulators/prboom-plus.yml b/emulators/prboom-plus.yml index 528debff2..912ff69bd 100644 --- a/emulators/prboom-plus.yml +++ b/emulators/prboom-plus.yml @@ -5,7 +5,11 @@ source: "https://github.com/coelckers/prboom-plus" upstream: "https://github.com/coelckers/prboom-plus" profiled_date: "2026-08-08" source_commit: "969515162c5aebea4ad7a125ee178dcad3d576ad" -core_version: "2.6.66" +core_version: "v2.6.66" +version_basis: + kind: tag + tag: "v2.6.66" + distance: 0 display_name: "Doom (PrBoom+)" cores: - prboom-plus diff --git a/emulators/prboom.yml b/emulators/prboom.yml index 15a47166d..c872f169f 100644 --- a/emulators/prboom.yml +++ b/emulators/prboom.yml @@ -6,6 +6,10 @@ upstream: "http://prboom.sourceforge.net/" profiled_date: "2026-10-23" source_commit: "4849268e7342494193f2bbf2d0128a751cf58da7" core_version: "v2.5.0" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Doom (PrBoom)" cores: [prboom] systems: [doom, heretic] diff --git a/emulators/primehack.yml b/emulators/primehack.yml index acf4a39bf..4003bc560 100644 --- a/emulators/primehack.yml +++ b/emulators/primehack.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-26" source_commit: "53f53e0f5bad27ad62a807cb93b136d84f68777f" upstream_commit: "d8558142ead21b3fa39809c4aedb982fbfc85feb" core_version: "1.0.9" +version_basis: + kind: tag + tag: "1.0.9" + distance: 0 display_name: "PrimeHack (Dolphin fork for Metroid Prime)" cores: - primehack diff --git a/emulators/project64.yml b/emulators/project64.yml index dbcd0982d..ce6f6907e 100644 --- a/emulators/project64.yml +++ b/emulators/project64.yml @@ -6,6 +6,11 @@ upstream: "https://github.com/project64/project64" profiled_date: "2026-08-12" source_commit: "24376e868350792a181d2121fec20d37354559d6" core_version: "Dev-4.0.0" +version_basis: + kind: file + path: "Source/Project64-core/Version.h.in" + pattern: '#define VERSION_MAJOR\s+(\d+)\s*\n#define VERSION_MINOR\s+(\d+)\s*\n#define VERSION_REVISION\s+(\d+)[\s\S]*?#define VERSION_PREFIX\s+"([^"]*)"' + format: "{4}{1}.{2}.{3}" display_name: "Nintendo - Nintendo 64 (Project64)" cores: - project64 diff --git a/emulators/prosystem.yml b/emulators/prosystem.yml index 20095165a..316f3834d 100644 --- a/emulators/prosystem.yml +++ b/emulators/prosystem.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/gstanton/ProSystem1_3" profiled_date: "2026-03-24" source_commit: "8a88014287c7a01cd568067e5a557d0a2b2a051f" core_version: "1.3e" +version_basis: + kind: file + path: "core/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Atari - 7800 (ProSystem)" cores: - prosystem diff --git a/emulators/psxmame.yml b/emulators/psxmame.yml index dcc296205..31a2bb042 100644 --- a/emulators/psxmame.yml +++ b/emulators/psxmame.yml @@ -5,7 +5,11 @@ source: "https://github.com/mamedev/mame" upstream: "https://github.com/mamedev/mame" profiled_date: "2026-10-20" source_commit: "0fdce58484202265b0794a77652bb5e3da9c56af" -core_version: "0.133" +core_version: "mame0133" +version_basis: + kind: tag + tag: "mame0133" + distance: 0 display_name: "Arcade PSX boards (pSxMAME)" mode: standalone cores: diff --git a/emulators/puae.yml b/emulators/puae.yml index 374b4d569..f58d30b8c 100644 --- a/emulators/puae.yml +++ b/emulators/puae.yml @@ -7,6 +7,10 @@ upstream: "https://github.com/GnoStiC/PUAE" profiled_date: "2026-03-24" source_commit: "7387937066b1b693816c3b4e2b7a0c601d41363d" core_version: "5.3.1" +version_basis: + kind: file + path: "retrodep/sysconfig.h" + pattern: '^#define VERSION "([^"]+)"' display_name: "Commodore - Amiga (PUAE)" systems: - commodore-amiga diff --git a/emulators/puae2021.yml b/emulators/puae2021.yml index 8bca713fd..13490fe13 100644 --- a/emulators/puae2021.yml +++ b/emulators/puae2021.yml @@ -7,6 +7,10 @@ upstream: "https://github.com/GnoStiC/PUAE" profiled_date: "2026-03-24" source_commit: "151828f14d43bb2b0651327ee19a23b36a7081b2" core_version: "2.6.1" +version_basis: + kind: file + path: "retrodep/sysconfig.h" + pattern: '^#define PACKAGE_VERSION "([^"]+)"' display_name: "Commodore - Amiga (PUAE 2021)" systems: - commodore-amiga diff --git a/emulators/punes.yml b/emulators/punes.yml index b8c9e6732..dbad94b43 100644 --- a/emulators/punes.yml +++ b/emulators/punes.yml @@ -6,6 +6,11 @@ upstream: "https://github.com/punesemu/puNES" profiled_date: "2026-08-08" source_commit: "b1758ec26a3d6da10abf50dc184fa837236c5f61" core_version: "0.112" +version_basis: + kind: file + path: "src/core/version.h" + pattern: '#define VER1\s+"(\d+)"[\s\S]*?#define VER2\s+"(\d+)"' + format: "{1}.{2}" display_name: "Nintendo - NES / Famicom (puNES)" cores: - punes diff --git a/emulators/puzzlescript.yml b/emulators/puzzlescript.yml index 33d4fae70..e8c3551a9 100644 --- a/emulators/puzzlescript.yml +++ b/emulators/puzzlescript.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/increpare/PuzzleScript" profiled_date: "2026-03-25" source_commit: "6d859b47092f585a7ec05804c1d51a1676a06531" core_version: "0.2.1" +version_basis: + kind: file + path: "src/core.cpp" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "PuzzleScript (pzretro)" cores: - puzzlescript diff --git a/emulators/px68k-sdl.yml b/emulators/px68k-sdl.yml index 87dbbf89c..36c3714bf 100644 --- a/emulators/px68k-sdl.yml +++ b/emulators/px68k-sdl.yml @@ -5,6 +5,10 @@ source: "https://github.com/TurtleBazooka/px68k" profiled_date: "2026-10-23" source_commit: "bdc3d87efb9f09df88c5c6eb271f9535aaf13210" core_version: "0.15+K" +version_basis: + kind: file + path: "version.txt" + pattern: '^PX68K_VERSION=(\S+)' display_name: "Sharp - X68000 (px68k SDL)" mode: standalone cores: ["px68k"] diff --git a/emulators/px68k.yml b/emulators/px68k.yml index c42869ed6..479d774b6 100644 --- a/emulators/px68k.yml +++ b/emulators/px68k.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/hissorii/px68k" profiled_date: "2026-03-25" source_commit: "5510637a4c0a08ac0302087ea498093dcc3e9d17" core_version: "0.15+" +version_basis: + kind: file + path: "libretro.c" + pattern: '#define\s+PX68K_VERSION\s+"([^"]+)' display_name: "Sharp - X68000 (PX68k)" cores: - px68k diff --git a/emulators/pygame.yml b/emulators/pygame.yml index 37bf7d8ef..bde9bb6ec 100644 --- a/emulators/pygame.yml +++ b/emulators/pygame.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/pygame/pygame" profiled_date: "2026-10-04" source_commit: "b92c0da9d1b5eba6c813138790fc1ab6cea0252c" core_version: "2.6.1" +version_basis: + kind: tag + tag: "2.6.1" + distance: 0 display_name: "Pygame" cores: [pygame, python-pygame2] systems: [] diff --git a/emulators/pyxel.yml b/emulators/pyxel.yml index 6e2206488..e15e203a7 100644 --- a/emulators/pyxel.yml +++ b/emulators/pyxel.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/kitao/pyxel" profiled_date: "2026-10-04" source_commit: "5d8e7b4f37c106684c1e91692772569a32a5e3d4" core_version: "v2.9.9" +version_basis: + kind: tag + tag: "v2.9.9" + distance: 0 display_name: "Pyxel" cores: [pyxel] systems: [] diff --git a/emulators/qemu.yml b/emulators/qemu.yml index 00edc9904..b8bce138b 100644 --- a/emulators/qemu.yml +++ b/emulators/qemu.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-25" source_commit: "aaba4471880587540314f82419d920431d55b769" upstream_commit: "d73149283205645625bfa9fe029cfb68e4c4a9ae" core_version: "0.1.0" +version_basis: + kind: file + path: "ui/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "QEMU" cores: [qemu] systems: [ibm-pc, x86, x86-64, ppc, ppc64, sparc, sparc64, arm, aarch64, mips, mips64, riscv32, riscv64, s390x, m68k, alpha, hppa] diff --git a/emulators/quake3.yml b/emulators/quake3.yml index cb30d9912..496b3fdfc 100644 --- a/emulators/quake3.yml +++ b/emulators/quake3.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/ioquake/ioq3" profiled_date: "2026-10-20" source_commit: "8d89a2a3c1707bf0f75b2ea26645b872e97c0b95" core_version: "1.35" +version_basis: + kind: file + path: "Makefile" + pattern: 'VERSION=([0-9][\w.+-]*)' display_name: "Quake III Arena (Raspberry Pi port)" cores: [quake3] systems: [quake3] diff --git a/emulators/quasi88.yml b/emulators/quasi88.yml index 649f801e6..c5a15fcd1 100644 --- a/emulators/quasi88.yml +++ b/emulators/quasi88.yml @@ -6,6 +6,10 @@ upstream: "https://www.retropc.net/showzoh/quasi88/" profiled_date: "2026-03-29" source_commit: "7884be5277776a5d8c4fdc4e574e9b5b589945c9" core_version: "0.6.4" +version_basis: + kind: file + path: "src/version.h" + pattern: '#define\s+Q_VERSION\s+"([^"]+)' display_name: "NEC - PC-8000 / PC-8800 series (QUASI88)" cores: - quasi88 diff --git a/emulators/quasi88kai.yml b/emulators/quasi88kai.yml index 714e22777..5f149dca2 100644 --- a/emulators/quasi88kai.yml +++ b/emulators/quasi88kai.yml @@ -5,6 +5,10 @@ source: "https://github.com/winterheart/quasi88" profiled_date: "2026-10-20" source_commit: "0d4e171415cad7ac19ae4ff0dcf8cdcfd825947b" core_version: "0.7.1" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: '^project\(quasi88 VERSION ([0-9.]+)\)' display_name: "NEC - PC-8800 series (QUASI88kai)" mode: standalone cores: ["quasi88"] diff --git a/emulators/quicknes.yml b/emulators/quicknes.yml index fa54b3dc5..cc4d670e4 100644 --- a/emulators/quicknes.yml +++ b/emulators/quicknes.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/kode54/QuickNES" profiled_date: "2026-03-25" source_commit: "26bb785c9deddb66a17717b21bb4e328f03ade32" core_version: "1.0-WIP" +version_basis: + kind: file + path: "libretro/libretro.cpp" + pattern: '#define\s+CORE_VERSION\s+"([^"]+)' display_name: "Nintendo - NES / Famicom (QuickNES)" cores: - quicknes diff --git a/emulators/race.yml b/emulators/race.yml index 8dc142550..c2f9cffff 100644 --- a/emulators/race.yml +++ b/emulators/race.yml @@ -7,6 +7,10 @@ profiled_date: "2026-09-17" source_commit: "c7810dd7f172827bfa2004813bc000b13786636b" upstream_commit: "065db2eb614d4414ed49a1a9e241022450bb844d" core_version: "v2.16" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: '#define\s+RACE_VERSION\s+"([^"]+)' display_name: "SNK - Neo Geo Pocket / Color (RACE)" cores: [race] systems: [snk-ngp, snk-ngpc] diff --git a/emulators/radio.yml b/emulators/radio.yml index 71fd56f7b..f677ed092 100644 --- a/emulators/radio.yml +++ b/emulators/radio.yml @@ -8,6 +8,10 @@ profiled_date: "2026-09-17" source_commit: "5d7d786ad1d8703a52184ff2ee39712c46ed67c9" upstream_commit: "5d7d786ad1d8703a52184ff2ee39712c46ed67c9" core_version: "1.1" +version_basis: + kind: file + path: "libretro-radio.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Internet Radio (Radio)" cores: - radio diff --git a/emulators/raine.yml b/emulators/raine.yml index 7d6d22639..df8fff733 100644 --- a/emulators/raine.yml +++ b/emulators/raine.yml @@ -7,6 +7,10 @@ profiled_date: "2026-10-20" source_commit: "8e25d5d8907ae459181610912b0030c955683015" pin_frozen: "RetroBat, the only platform that ships it, installs this release: the raine.exe of its raine.7z package (8 August 2026) reports 0.97.5 and was built on 16 March 2025, the bump its changelog records (RetroBat CHANGELOG.md:176). Later commits are not part of that package." core_version: "0.97.5" +version_basis: + kind: file + path: "makefile" + pattern: 'VERSION\s+=\s+"([^"]+)' display_name: "Arcade (RAINE)" mode: standalone cores: diff --git a/emulators/raze.yml b/emulators/raze.yml index 338a101aa..ae88fc8fc 100644 --- a/emulators/raze.yml +++ b/emulators/raze.yml @@ -5,6 +5,11 @@ source: "https://github.com/ZDoom/Raze" upstream: "https://github.com/ZDoom/Raze" profiled_date: "2026-10-04" source_commit: "76fe82f5eb318fdeb30ba9fb27093a9a10bc3821" +core_version: "1.12pre" +version_basis: + kind: file + path: "source/core/version.h" + pattern: '^#define VERSIONSTR "([^"]+)"' display_name: "Raze" cores: [] systems: [duke3d, blood, shadow-warrior, powerslave, exhumed, redneck, nam, ww2gi] diff --git a/emulators/rb5000.yml b/emulators/rb5000.yml index 9277193dc..01d9064db 100644 --- a/emulators/rb5000.yml +++ b/emulators/rb5000.yml @@ -13,6 +13,15 @@ pin_frozen: "Recalbox, the only platform that ships the standalone build, builds core_version: standalone: "v1.1" libretro: "v0.9" +version_basis: + standalone: + kind: tag + tag: "v1.1" + distance: 0 + libretro: + kind: tag + tag: "v0.9" + distance: 0 display_name: "Philips - VG 5000 (RB5000)" cores: - "rb5000" diff --git a/emulators/real3doplayer.yml b/emulators/real3doplayer.yml index f49bdb826..162002937 100644 --- a/emulators/real3doplayer.yml +++ b/emulators/real3doplayer.yml @@ -9,6 +9,11 @@ version_source: author: "AltmerSoft (Maxim Grishin)" profiled_date: "2026-08-12" core_version: "1.0.32" +version_basis: + kind: package + url: "http://www.arts-union.ru/node/23" + pattern: 'real3DOPlayer_free_(\d+(?:\.\d+)+)\.zip' + artifact: "real3DOPlayer_free_1.0.32.zip" display_name: "The 3DO Company - 3DO (Real3DOPlayer)" mode: standalone cores: diff --git a/emulators/realrtcw.yml b/emulators/realrtcw.yml index f518b8553..a39081333 100644 --- a/emulators/realrtcw.yml +++ b/emulators/realrtcw.yml @@ -7,6 +7,10 @@ profiled_date: "2026-10-20" source_commit: "ad529d588e4dec717aff0779f9d1555eddc1e2be" pin_frozen: "RetroBat, the only platform that ships it, installs this release: the RealRTCW.x64.exe of its rtcw.7z package (31 March 2026) reports RealRTCW 5.2. Later releases are not part of that package." core_version: "5.2" +version_basis: + kind: tag + tag: "5.2" + distance: 0 display_name: "RealRTCW" mode: standalone cores: diff --git a/emulators/redbook.yml b/emulators/redbook.yml index 521bae6af..19e872709 100644 --- a/emulators/redbook.yml +++ b/emulators/redbook.yml @@ -5,6 +5,10 @@ source: "https://github.com/libretro/redbook" profiled_date: "2026-03-25" source_commit: "43544bb988f37a8f3df5af5d2c6f89dd255b8235" core_version: "1.0" +version_basis: + kind: file + path: "libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Redbook Audio Player" cores: - redbook diff --git a/emulators/redream.yml b/emulators/redream.yml index 3f030d30f..251f8fdab 100644 --- a/emulators/redream.yml +++ b/emulators/redream.yml @@ -10,6 +10,10 @@ emulator: Redream type: libretro source: "https://github.com/libretro/redream" +core_version: null +version_basis: + kind: unverified + why: no_pin cores: - redream systems: diff --git a/emulators/reicast.yml b/emulators/reicast.yml index df036d350..975bcfa4c 100644 --- a/emulators/reicast.yml +++ b/emulators/reicast.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/skmp/reicast-emulator" profiled_date: "2026-10-17" source_commit: "ad61f95dd6b4c6218846a25de6194550311a5d28" pin_frozen: "Recalbox 10.1.1 builds this revision (package/reicast/reicast.mk REICAST_VERSION). Later commits on reicast-emulator are not part of that build." -core_version: "Git" +core_version: "r8.1-243-gad61f95" +version_basis: + kind: tag + tag: "r8.1" + distance: 243 display_name: "Sega - Dreamcast (Reicast)" cores: - "reicast" diff --git a/emulators/reminiscence.yml b/emulators/reminiscence.yml index a5a504218..4bf1ff22e 100644 --- a/emulators/reminiscence.yml +++ b/emulators/reminiscence.yml @@ -7,6 +7,10 @@ upstream_commit: "947a4dce261aacc4f6ec0c2c90cb9d7e37712c7b" profiled_date: "2026-03-25" source_commit: "e6c0b0039258004f8bc377ddb88c0e931db131ce" core_version: "0.3.6" +version_basis: + kind: file + path: "src/libretro.cpp" + pattern: '#define\s+RE_VERSION\s+"([^"]+)' display_name: "Flashback (REminiscence)" cores: - reminiscence diff --git a/emulators/remotejoy.yml b/emulators/remotejoy.yml index 5db39b9fc..8d204628f 100644 --- a/emulators/remotejoy.yml +++ b/emulators/remotejoy.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/akiraink/RemoteJoyLite" profiled_date: "2026-03-25" source_commit: "745b97ca8d2d825d0bfde4bb321d1bf7b49fd91d" core_version: "v1" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "PSP RemotePlay (RemoteJoy)" cores: - remotejoy diff --git a/emulators/retro8.yml b/emulators/retro8.yml index 5354378d7..a27f50183 100644 --- a/emulators/retro8.yml +++ b/emulators/retro8.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-25" source_commit: "ddc06a142398ee9755894b3f0bb17c8dc428151d" upstream_commit: "ecee6594c5b953966ee0515f3edac4032c7ed40f" core_version: "0.1b" +version_basis: + kind: file + path: "src/libretro/libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "PICO-8 (Retro8)" cores: - retro8 diff --git a/emulators/retrodream.yml b/emulators/retrodream.yml index 3154bfe27..0d0c76fba 100644 --- a/emulators/retrodream.yml +++ b/emulators/retrodream.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/redream-next" upstream: "https://github.com/inolen/redream" profiled_date: "2026-03-25" source_commit: "d826ece7f987c6fed336246e7272e2ded6cefa69" -core_version: "Git" +core_version: "0.0" +version_basis: + kind: file + path: "src/host/retro_host.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "Sega - Dreamcast (RetroDream)" cores: - retrodream diff --git a/emulators/rigelengine.yml b/emulators/rigelengine.yml index 6c877abee..880db6916 100644 --- a/emulators/rigelengine.yml +++ b/emulators/rigelengine.yml @@ -5,7 +5,11 @@ source: "https://github.com/lethal-guitar/RigelEngine" upstream: "https://github.com/lethal-guitar/RigelEngine" profiled_date: "2026-10-22" source_commit: "30afeff8f0b105eac77ee0a2fbd54b06e1a49b60" -core_version: "0.9.1-28-g30afeff8" +core_version: "0.9.1" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: '^project\(RigelEngine VERSION ([0-9.]+)\)' display_name: "Duke Nukem II (RigelEngine)" cores: [rigelengine, "RigelEngine"] systems: [duke-nukem-2] diff --git a/emulators/romcleaner.yml b/emulators/romcleaner.yml index 5bc706fdd..2abacb6f0 100644 --- a/emulators/romcleaner.yml +++ b/emulators/romcleaner.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/JesseTG/rom-cleaner" profiled_date: "2026-03-25" source_commit: "f75e2b58733de180f28a73286c6a82505be7bbb2" core_version: "1.0.0" +version_basis: + kind: file + path: "libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "ROM Cleaner" cores: - romcleaner diff --git a/emulators/rosalies-mupen-gui.yml b/emulators/rosalies-mupen-gui.yml index 8bfab72d7..310b0c6f7 100644 --- a/emulators/rosalies-mupen-gui.yml +++ b/emulators/rosalies-mupen-gui.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/Rosalie241/RMG" profiled_date: "2026-10-04" source_commit: "4777ed3f1fb7f1e4a0e70438a27dc4a5e9fb1927" core_version: "v0.9.0" +version_basis: + kind: file + path: "VERSION" + pattern: '^(v?[0-9][^\s]*)' display_name: "Nintendo - Nintendo 64 (Rosalie's Mupen GUI)" cores: - rosalies-mupen-gui diff --git a/emulators/rp6502.yml b/emulators/rp6502.yml index e59932a09..65dc4d15c 100644 --- a/emulators/rp6502.yml +++ b/emulators/rp6502.yml @@ -6,7 +6,11 @@ source_branch: libretro upstream: "https://github.com/picocomputer/rp6502" profiled_date: "2026-09-17" source_commit: "02bfc3cbc9b2700795ce0a40fb49b413784cb832" -core_version: "0.33" +core_version: "v0.33" +version_basis: + kind: tag + tag: "v0.33" + distance: 0 display_name: "Picocomputer 6502" cores: - rp6502 diff --git a/emulators/rpcs3.yml b/emulators/rpcs3.yml index 5f3a0a146..ea5e70862 100644 --- a/emulators/rpcs3.yml +++ b/emulators/rpcs3.yml @@ -8,7 +8,12 @@ cores: - "rpcs3-sa" profiled_date: "2026-03-30" source_commit: "c365ea76a552961ff078ea1a46da9d4b07729674" -core_version: "v0.0.43" +core_version: "0.0.43" +version_basis: + kind: file + path: "rpcs3/rpcs3_version.cpp" + pattern: 'utils::version version\{\s*(\d+),\s*(\d+),\s*(\d+),' + format: "{1}.{2}.{3}" display_name: "Sony - PlayStation 3 (RPCS3)" systems: [sony-playstation-3] diff --git a/emulators/rpix86.yml b/emulators/rpix86.yml index ff3530143..62e7d5737 100644 --- a/emulators/rpix86.yml +++ b/emulators/rpix86.yml @@ -5,6 +5,10 @@ source: "http://rpix86.patrickaalto.com/rdown.html" upstream: ~ profiled_date: "2026-10-20" core_version: "0.19" +version_basis: + kind: package + url: "https://files.retropie.org.uk/archives/rpix86.tar.gz" + artifact: "rpix86.tar.gz, rpix86 binary banner" display_name: "DOS (rpix86)" cores: [rpix86] systems: [dos] diff --git a/emulators/ruffle.yml b/emulators/ruffle.yml index 8a08c4847..2c91a71db 100644 --- a/emulators/ruffle.yml +++ b/emulators/ruffle.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/ruffle-rs/ruffle" profiled_date: "2026-09-17" source_commit: "fe6cfc545405b888ebb478ce1c211d63147ca49b" core_version: "0.7.1" +version_basis: + kind: file + path: "Cargo.toml" + pattern: 'version\s+=\s+"([^"]+)' display_name: "Adobe Flash (Ruffle)" cores: - ruffle diff --git a/emulators/rust_dos.yml b/emulators/rust_dos.yml index 4fa4caebc..511114a3d 100644 --- a/emulators/rust_dos.yml +++ b/emulators/rust_dos.yml @@ -7,6 +7,10 @@ profiled_date: "2026-10-04" source_commit: "152d9bca7820f0d9a5d1ca820a2d20855698a211" upstream_commit: "152d9bca7820f0d9a5d1ca820a2d20855698a211" core_version: "1.7.5" +version_basis: + kind: file + path: "Cargo.toml" + pattern: 'version\s+=\s+"([^"]+)' display_name: "DOS (Rust-DOS)" cores: - rust_dos diff --git a/emulators/rustation.yml b/emulators/rustation.yml index e2f5238f4..699ba38e5 100644 --- a/emulators/rustation.yml +++ b/emulators/rustation.yml @@ -6,7 +6,12 @@ upstream: "https://github.com/simias/rustation" profiled_date: "2026-03-25" source_commit: "3e328e3967e312e1f239aeeecd479a7b4bfda850" upstream_commit: "1daf4faaade3c0fd1e9deace8e309e91303f1b46" -core_version: "v1" +core_version: "0.0.1" +version_basis: + kind: file + repo: upstream + path: "Cargo.toml" + pattern: '^version\s*=\s*"([^"]+)"' display_name: "Sony - PlayStation (Rustation)" cores: [rustation] found_by: content diff --git a/emulators/rustynes.yml b/emulators/rustynes.yml index 528aca632..aa6999fd5 100644 --- a/emulators/rustynes.yml +++ b/emulators/rustynes.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/doublegate/RustyNES" profiled_date: "2026-10-26" source_commit: "3d02b99dc84fb389c03fc6b1f986ffa658dda0dd" core_version: "3.5.0" +version_basis: + kind: file + path: "Cargo.toml" + pattern: 'version\s+=\s+"([^"]+)' display_name: "Nintendo - NES / Famicom (RustyNES)" cores: - rustynes diff --git a/emulators/rvvm.yml b/emulators/rvvm.yml index 243610825..21184b7be 100644 --- a/emulators/rvvm.yml +++ b/emulators/rvvm.yml @@ -5,7 +5,11 @@ source: "https://github.com/LekKit/RVVM" upstream: "https://github.com/LekKit/RVVM" profiled_date: "2026-03-25" source_commit: "343f6784c8922446083c5d5bd111d7c1eb8590eb" -core_version: "0.7-git" +core_version: "0.7" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: '^set\(RVVM_VERSION ([0-9.]+)\)' display_name: "RVVM" cores: [rvvm] systems: [riscv] diff --git a/emulators/ryujinx.yml b/emulators/ryujinx.yml index 4d75ef4ea..50fc96065 100644 --- a/emulators/ryujinx.yml +++ b/emulators/ryujinx.yml @@ -5,6 +5,10 @@ upstream: "https://github.com/Ryujinx/Ryujinx" profiled_date: "2026-03-26" source_commit: "7d158acc3b5826a08941d6e8d50d3a3897021bcd" core_version: "1.1.1402" +version_basis: + kind: tag + tag: "1.1.1402" + distance: 0 display_name: "Ryujinx (Nintendo Switch)" cores: - ryujinx diff --git a/emulators/samcoupe.yml b/emulators/samcoupe.yml index 18eba3027..46958b976 100644 --- a/emulators/samcoupe.yml +++ b/emulators/samcoupe.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/simonowen/simcoupe" profiled_date: "2026-10-04" source_commit: "1f966036543991c05022ce4f95cfbfbb0014b187" core_version: "v1.2.17" +version_basis: + kind: tag + tag: "v1.2.17" + distance: 0 display_name: "SAM Coupe (SimCoupe)" cores: - samcoupe diff --git a/emulators/same_cdi.yml b/emulators/same_cdi.yml index 545108df6..5b5c1914e 100644 --- a/emulators/same_cdi.yml +++ b/emulators/same_cdi.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/mamedev/mame" profiled_date: "2026-03-25" source_commit: "ff9bb99a50d518aef6d2add1c49b7c44447e3e78" upstream_commit: "39eb9e44c394df9aec8186f2d2ef7517ace232e1" -core_version: "Git" +core_version: "0.287" +version_basis: + kind: file + path: "gen/version.cpp" + pattern: '#define\s+BARE_BUILD_VERSION\s+"([^"]+)"' display_name: "Philips - CDi (SAME CDi)" cores: [same_cdi] systems: diff --git a/emulators/sameboy.yml b/emulators/sameboy.yml index 6c0635d4d..fc727a438 100644 --- a/emulators/sameboy.yml +++ b/emulators/sameboy.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-25" source_commit: "aa158a889a48b538a0302873704a34577c8eb67d" upstream_commit: "9bf7e0b4dffc20941e4dfadffc6899ae19463844" core_version: "0.15.4" +version_basis: + kind: file + path: "version.mk" + pattern: 'VERSION\s+:=\s+([0-9][\w.+-]*)' display_name: "Nintendo - Game Boy / Color (SameBoy)" cores: - sameboy diff --git a/emulators/sameduck.yml b/emulators/sameduck.yml index 07d09653a..2d867fa39 100644 --- a/emulators/sameduck.yml +++ b/emulators/sameduck.yml @@ -6,6 +6,9 @@ upstream: "https://github.com/LIJI32/SameBoy" profiled_date: "2026-03-25" source_commit: "e7da9386e1533268b7e9de73450e070b1498d1bf" core_version: "0.13.6" +version_basis: + kind: unverified + why: pin_off_branch display_name: "Mega Duck / Cougar Boy (SameDuck)" cores: - sameduck diff --git a/emulators/saturn-emu.yml b/emulators/saturn-emu.yml index 5983e977c..bcfb16a67 100644 --- a/emulators/saturn-emu.yml +++ b/emulators/saturn-emu.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-08-12" source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/metadata/conf.mk" + pattern: '^metadata_version\s*=\s*(\S+)' display_name: "Sega - Saturn (Saturn.emu)" mode: standalone cores: diff --git a/emulators/scummvm-sdl1.yml b/emulators/scummvm-sdl1.yml index 61b43c94c..557b027f5 100644 --- a/emulators/scummvm-sdl1.yml +++ b/emulators/scummvm-sdl1.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/scummvm/scummvm" logo: "https://raw.githubusercontent.com/scummvm/scummvm/master/icons/scummvm.svg" profiled_date: "2026-10-20" source_commit: "fed42f2068dcafc6aafa1c28c77e4c88def74b66" -core_version: "2026.3.0" +core_version: "v2026.3.0" +version_basis: + kind: tag + tag: "v2026.3.0" + distance: 0 display_name: "ScummVM (SDL1)" cores: [scummvm-sdl1] systems: [scummvm] diff --git a/emulators/scummvm-standalone.yml b/emulators/scummvm-standalone.yml index e7bc5aef6..468f14c25 100644 --- a/emulators/scummvm-standalone.yml +++ b/emulators/scummvm-standalone.yml @@ -6,6 +6,10 @@ logo: "https://raw.githubusercontent.com/scummvm/scummvm/master/icons/scummvm.sv profiled_date: "2026-10-24" source_commit: "21955df19b580dad2807ec55f573b5f348690a81" core_version: "2026.4.1git" +version_basis: + kind: file + path: "base/internal_version.h" + pattern: '#define\s+SCUMMVM_VERSION\s+"([^"]+)' display_name: "ScummVM (SDL2)" mode: standalone cores: diff --git a/emulators/scummvm.yml b/emulators/scummvm.yml index adb0bfcdb..f8241807d 100644 --- a/emulators/scummvm.yml +++ b/emulators/scummvm.yml @@ -7,7 +7,11 @@ logo: "https://raw.githubusercontent.com/scummvm/scummvm/master/icons/scummvm.sv profiled_date: "2026-03-25" source_commit: "e0ddc60bfabb1efdf1e135006c8914ca59d0596c" upstream_commit: "e0ddc60bfabb1efdf1e135006c8914ca59d0596c" -core_version: "2.8.0git" +core_version: "2026.4.1git" +version_basis: + kind: file + path: "base/internal_version.h" + pattern: '#define SCUMMVM_VERSION "([^"]+)"' display_name: "ScummVM" cores: [scummvm] systems: [scummvm] diff --git a/emulators/sdl2trs.yml b/emulators/sdl2trs.yml index 31618b4a9..cf4a452b2 100644 --- a/emulators/sdl2trs.yml +++ b/emulators/sdl2trs.yml @@ -6,6 +6,10 @@ upstream: "http://sdltrs.sourceforge.net" profiled_date: "2026-10-23" source_commit: "205ddfd78fd00b32b3f730453175dbd70782ce79" core_version: "1.2.35" +version_basis: + kind: file + path: "configure.ac" + pattern: '^AC_INIT\(\[sdltrs\],\s*\[([^\]]+)\]' display_name: "Tandy - TRS-80 (SDL2TRS)" cores: - sdl2trs diff --git a/emulators/sdlpal.yml b/emulators/sdlpal.yml index e1aa2234c..d189676c8 100644 --- a/emulators/sdlpal.yml +++ b/emulators/sdlpal.yml @@ -5,7 +5,11 @@ source: "https://github.com/sdlpal/sdlpal" upstream: "https://github.com/sdlpal/sdlpal" profiled_date: "2026-03-25" source_commit: "d4bf69b64d335cd680555af9df90e7ec4f3006a3" -core_version: "v2.0.1" +core_version: "2.0.1" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "SDLPAL" cores: - sdlpal diff --git a/emulators/sdlpop.yml b/emulators/sdlpop.yml index 94511bd73..822451fb9 100644 --- a/emulators/sdlpop.yml +++ b/emulators/sdlpop.yml @@ -6,6 +6,10 @@ upstream: ~ profiled_date: "2026-10-04" source_commit: "3c5add5fb7f83d4ceb542823ab66d00146c4271b" core_version: "1.24 RC" +version_basis: + kind: file + path: "src/config.h" + pattern: '#define SDLPOP_VERSION "([^"]+)"' display_name: "Prince of Persia (SDLPoP)" cores: [sdlpop, "prince"] systems: [prince-of-persia] diff --git a/emulators/shadps4.yml b/emulators/shadps4.yml index d78aa1f34..4256ad93e 100644 --- a/emulators/shadps4.yml +++ b/emulators/shadps4.yml @@ -4,7 +4,12 @@ source: "https://github.com/shadps4-emu/shadPS4" upstream: "https://github.com/shadps4-emu/shadPS4" profiled_date: "2026-03-26" source_commit: "3eecea94ddaca360b19f4b800523b609a8b2ffcc" -core_version: "pre-release 2026-08-08" +core_version: "0.20.1 WIP" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'set\(EMULATOR_VERSION_MAJOR "(\d+)"\)\s*\nset\(EMULATOR_VERSION_MINOR "(\d+)"\)\s*\nset\(EMULATOR_VERSION_PATCH "(\d+)"\)[\s\S]*?set\(APP_VERSION "\$\{APP_VERSION_NUM\} ?([^"]*)"\)' + format: "{1}.{2}.{3} {4}" display_name: "shadPS4 (PlayStation 4)" cores: - shadps4 diff --git a/emulators/sheepshaver.yml b/emulators/sheepshaver.yml index 916d9b2d2..cd58251e4 100644 --- a/emulators/sheepshaver.yml +++ b/emulators/sheepshaver.yml @@ -6,6 +6,11 @@ upstream: "https://github.com/cebix/macemu" profiled_date: "2026-08-08" source_commit: "96e512bd6376e78a2869f16dcc8a9028bce5ee72" core_version: "2.4" +version_basis: + kind: file + path: "SheepShaver/src/include/version.h" + pattern: 'const int VERSION_MAJOR = (\d+);\s*\nconst int VERSION_MINOR = (\d+);' + format: "{1}.{2}" display_name: "Apple - Macintosh PowerPC (SheepShaver)" cores: - sheepshaver diff --git a/emulators/simcp.yml b/emulators/simcp.yml index 2c70a88f5..cec35b264 100644 --- a/emulators/simcp.yml +++ b/emulators/simcp.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/libretro-simcoupe" upstream: "https://github.com/simonowen/simcoupe" profiled_date: "2026-03-25" source_commit: "c28046241ac6a4d79e55326b6e354dc02f92fa34" -core_version: "Git" +core_version: "v1.1 alpha" +version_basis: + kind: file + path: "SimCoupe/Base/GUIDlg.cpp" + pattern: 'szVersion\[128\] = "SimCoupe (v[^"]+)"' display_name: "SAM Coupe (SimCoupe)" cores: - simcp diff --git a/emulators/simple64.yml b/emulators/simple64.yml index 8948aad56..f09be5b1d 100644 --- a/emulators/simple64.yml +++ b/emulators/simple64.yml @@ -5,7 +5,11 @@ source: "https://github.com/simple64/simple64" upstream: "https://github.com/simple64/simple64" profiled_date: "2026-08-08" source_commit: "d8c969c7b932e3d76e6a25549d76348839dbaefd" -core_version: "v2024.12.1" +core_version: "v2024.12.1-5-gd8c969c" +version_basis: + kind: tag + tag: "v2024.12.1" + distance: 5 display_name: "Nintendo - Nintendo 64 (simple64)" cores: - simple64 diff --git a/emulators/singe2.yml b/emulators/singe2.yml index 3f617744a..0da384e39 100644 --- a/emulators/singe2.yml +++ b/emulators/singe2.yml @@ -5,6 +5,11 @@ source: "https://singeengine.com" upstream: "https://singeengine.com" profiled_date: "2026-10-20" core_version: "2.10" +version_basis: + kind: package + url: "https://singeengine.com" + pattern: 'Singe-v(\d+\.\d+)-Windows' + artifact: "Singe-v2.10-Windows-x86_64.exe" display_name: "Laserdisc (Singe 2)" mode: standalone cores: diff --git a/emulators/sixtyforce.yml b/emulators/sixtyforce.yml index 153ace7d7..d9d5dc34a 100644 --- a/emulators/sixtyforce.yml +++ b/emulators/sixtyforce.yml @@ -8,6 +8,10 @@ version_source: pattern: 'version (\d+(?:\.\d+)+)<br>' profiled_date: "2026-08-12" core_version: "2.0.2" +version_basis: + kind: package + url: "https://sixtyforce.com/download/sixtyforce.zip" + artifact: "sixtyforce.zip, sixtyforce.app Info.plist CFBundleShortVersionString" display_name: "Nintendo - Nintendo 64 (sixtyforce)" cores: - sixtyforce diff --git a/emulators/skyemu.yml b/emulators/skyemu.yml index 56db786ff..da6afa3e7 100644 --- a/emulators/skyemu.yml +++ b/emulators/skyemu.yml @@ -5,7 +5,11 @@ source: https://github.com/skylersaleh/SkyEmu/blob/v5/src/libretro.c upstream: https://github.com/skylersaleh/SkyEmu profiled_date: "2026-03-25" source_commit: "f4d3238bf42da483ed1b7cc35649398b2110e4b4" -core_version: "v5" +core_version: "v5-22-gf4d3238" +version_basis: + kind: tag + tag: "v5" + distance: 22 display_name: "Nintendo - Game Boy/GBA/NDS (SkyEmu)" cores: diff --git a/emulators/skyline.yml b/emulators/skyline.yml index ea0b99926..368ac18ed 100644 --- a/emulators/skyline.yml +++ b/emulators/skyline.yml @@ -6,6 +6,9 @@ upstream: "https://archive.softwareheritage.org/browse/revision/dc20a615275f66be profiled_date: "2026-08-12" source_commit: "dc20a615275f66bee20a4fd851ef0231daca4f14" core_version: "0.0.3" +version_basis: + kind: unverified + why: host_unsupported display_name: "Nintendo - Switch (Skyline)" cores: - "skyline" diff --git a/emulators/smsplus.yml b/emulators/smsplus.yml index 1ed5fd3db..a358b3563 100644 --- a/emulators/smsplus.yml +++ b/emulators/smsplus.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/ekeeke/smsplus-gx" profiled_date: "2026-03-25" source_commit: "3844b46caa926b6494987b97da63092818c4ddef" core_version: "1.8" +version_basis: + kind: file + path: "source/system.h" + pattern: '#define\s+APP_VERSION\s+"([^"]+)"' display_name: "Sega - MS/GG (SMS Plus GX)" cores: - smsplus diff --git a/emulators/snes9x-explus.yml b/emulators/snes9x-explus.yml index fc00ed6e1..19c86b43c 100644 --- a/emulators/snes9x-explus.yml +++ b/emulators/snes9x-explus.yml @@ -8,6 +8,10 @@ source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" upstream_commit: "b33f2afb33c61d675aaf0319bd3b8cc8d6924d49" upstream_frozen: "Snes9x is vendored under Snes9x/src/snes9x at this upstream revision, the one the last sync took." core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/metadata/conf.mk" + pattern: '^metadata_version\s*=\s*(\S+)' display_name: "Nintendo - SNES / SFC (Snes9x EX+)" mode: standalone cores: diff --git a/emulators/snes9x.yml b/emulators/snes9x.yml index d1c0f2018..f79667dc1 100644 --- a/emulators/snes9x.yml +++ b/emulators/snes9x.yml @@ -7,7 +7,11 @@ logo: "https://raw.githubusercontent.com/snes9xgit/snes9x/master/gtk/data/snes9x profiled_date: "2026-03-25" source_commit: "fae2fea08f74180759ef540ee94259213f503480" upstream_commit: "85591435763dede7ef111aab8070cdf2d5a7da49" -core_version: "1.61" +core_version: "1.63" +version_basis: + kind: file + path: "snes9x.h" + pattern: '#define\s+VERSION\s+"([^"]+)"' display_name: "Nintendo - SNES / SFC (Snes9x)" systems: [nintendo-snes, nintendo-satellaview, nintendo-sufami-turbo] diff --git a/emulators/snes9x2002.yml b/emulators/snes9x2002.yml index 4404cdef9..69434ffbf 100644 --- a/emulators/snes9x2002.yml +++ b/emulators/snes9x2002.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-25" source_commit: "6ffbf9ef4f0063e1f1b78a40d10c50fc52f2524c" upstream_commit: "1bcc369e89f08243e0a462882fb1f3e42e51de3a" core_version: "7.2.0" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Nintendo - SNES / SFC (Snes9x 2002)" cores: - snes9x2002 diff --git a/emulators/snes9x2005.yml b/emulators/snes9x2005.yml index 1f9888dba..238979162 100644 --- a/emulators/snes9x2005.yml +++ b/emulators/snes9x2005.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/ShadauxCat/CATSFC" profiled_date: "2026-03-25" source_commit: "a79dfe9047e7fec58808aefe48ad2bf499c7af11" core_version: "v1.36" +version_basis: + kind: file + path: "libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Nintendo - SNES / SFC (Snes9x 2005)" cores: - snes9x2005 diff --git a/emulators/snes9x2005_plus.yml b/emulators/snes9x2005_plus.yml index 1045e6f08..baa875351 100644 --- a/emulators/snes9x2005_plus.yml +++ b/emulators/snes9x2005_plus.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/ShadauxCat/CATSFC" profiled_date: "2026-03-25" source_commit: "a79dfe9047e7fec58808aefe48ad2bf499c7af11" core_version: "v1.36" +version_basis: + kind: file + path: "libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Nintendo - SNES / SFC (Snes9x 2005 Plus)" cores: - snes9x2005_plus diff --git a/emulators/snes9x2010.yml b/emulators/snes9x2010.yml index 68598a425..93541ac2d 100644 --- a/emulators/snes9x2010.yml +++ b/emulators/snes9x2010.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/snes9xgit/snes9x" profiled_date: "2026-03-25" source_commit: "fe690dd321fa5a46b5234a2bde089d2518c62b0e" upstream_commit: "1bcc369e89f08243e0a462882fb1f3e42e51de3a" -core_version: "v1.52.4" +core_version: "1.52.4" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: '#define\s+CORE_VERSION\s+"([^"]+)' display_name: "Nintendo - SNES / SFC (Snes9x 2010)" cores: - snes9x2010 diff --git a/emulators/soh.yml b/emulators/soh.yml index 7b4f087ad..045497315 100644 --- a/emulators/soh.yml +++ b/emulators/soh.yml @@ -7,6 +7,10 @@ source_commit: "cb71e22a79bc5d1f688fa881795bbd93094895fc" pin_frozen: "RetroBat, the only platform that ships it, installs this release: the soh.exe of its soh.7z package (10 October 2026) reports Ackbar Delta (9.2.3). Later releases are not part of that package." profiled_date: "2026-10-20" core_version: "9.2.3" +version_basis: + kind: tag + tag: "9.2.3" + distance: 0 display_name: "The Legend of Zelda: Ocarina of Time (Ship of Harkinian)" cores: [soh] systems: [soh] diff --git a/emulators/solarus-2.0.0.yml b/emulators/solarus-2.0.0.yml index 62b17785c..e1baae42a 100644 --- a/emulators/solarus-2.0.0.yml +++ b/emulators/solarus-2.0.0.yml @@ -7,6 +7,10 @@ profiled_date: "2026-10-26" source_commit: "49d1d4686f67ec81c86c90ca30279a4ce06b1729" pin_frozen: "RetroBat, the only platform that ships it, builds this revision: the solarus2 package its emulator repository lists as 0.25.04.16 carries a libsolarus.dll that reports Solarus 2.0.0 (49d1d46), tag v2.0.0+cicd1. Later tags are not part of that build." core_version: "2.0.0" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'project\(solarus-engine\s+VERSION\s+([0-9][^\s)]*)' display_name: "Solarus Game Engine (2.0.0)" cores: - solarus2 diff --git a/emulators/solarus.yml b/emulators/solarus.yml index 54b056798..00112eee0 100644 --- a/emulators/solarus.yml +++ b/emulators/solarus.yml @@ -6,6 +6,10 @@ upstream: "https://gitlab.com/solarus-games/solarus" profiled_date: "2026-08-08" source_commit: "86fa2031e1303aaaf9924a2f03dfdb7b7d1cbf4b" core_version: "2.2.0" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'project\(solarus-engine\s+VERSION\s+([0-9][^\s)]*)' display_name: "Solarus Game Engine" cores: - solarus diff --git a/emulators/sonic-mania.yml b/emulators/sonic-mania.yml index dfff57eee..4b1a93b05 100644 --- a/emulators/sonic-mania.yml +++ b/emulators/sonic-mania.yml @@ -5,6 +5,11 @@ source: "https://github.com/RSDKModding/Sonic-Mania-Decompilation" upstream: "https://github.com/RSDKModding/RSDKv5-Decompilation" source_commit: "9dc699428420d752af9767bdb13f585ee0881bc0" upstream_commit: "191d7aea6c262d891244172a8609ac69fbfd7571" +core_version: "v1.1.1-15-g9dc6994" +version_basis: + kind: tag + tag: "v1.1.1" + distance: 15 profiled_date: "2026-10-04" display_name: "Sonic Mania (RSDKv5 Decomp)" cores: [sonicmania] diff --git a/emulators/sonic2013.yml b/emulators/sonic2013.yml index 3fc9f9363..8dfd837fa 100644 --- a/emulators/sonic2013.yml +++ b/emulators/sonic2013.yml @@ -5,6 +5,10 @@ source: "https://github.com/RSDKModding/RSDKv4-Decompilation" upstream: "https://github.com/RSDKModding/RSDKv4-Decompilation" source_commit: "a7f5195e21fdad7b75e4587e249013feeea9e6f3" core_version: "1.3.3" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'set\(DECOMP_VERSION\s+([^\s)]+)\)' profiled_date: "2026-10-04" display_name: "Sonic 1 & 2 (2013) (RSDKv4 Decomp)" cores: [sonicretro] diff --git a/emulators/sonic3-air.yml b/emulators/sonic3-air.yml index 4df14d223..c1e6220d9 100644 --- a/emulators/sonic3-air.yml +++ b/emulators/sonic3-air.yml @@ -4,6 +4,11 @@ core_classification: game_engine source: "https://github.com/Eukaryot/sonic3air" upstream: "https://github.com/Eukaryot/sonic3air" source_commit: "b0063dfb4b3e69d710e131ab83507cdf8c41910f" +core_version: "26.08.15.0" +version_basis: + kind: file + path: "Oxygen/sonic3air/source/sonic3air/version.inc" + pattern: '#define\s+BUILD_STRING\s+"([^"]+)"' profiled_date: "2026-10-04" display_name: "Sonic 3 - Angel Island Revisited" cores: [sonic3air] diff --git a/emulators/soniccd.yml b/emulators/soniccd.yml index 65fd5654c..d42016b92 100644 --- a/emulators/soniccd.yml +++ b/emulators/soniccd.yml @@ -4,6 +4,11 @@ core_classification: game_engine source: "https://github.com/RSDKModding/RSDKv3-Decompilation" upstream: "https://github.com/RSDKModding/RSDKv3-Decompilation" source_commit: "2a7fd8b70f1b33553e0d6c67491d07e8290b80c1" +core_version: "1.3.3" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'set\(DECOMP_VERSION\s+([^\s)]+)\)' profiled_date: "2026-10-04" display_name: "Sonic CD (RSDKv3 Decomp)" cores: [sonicretrocd] diff --git a/emulators/speccy.yml b/emulators/speccy.yml index 72b6e64c3..cfa22dd4b 100644 --- a/emulators/speccy.yml +++ b/emulators/speccy.yml @@ -9,6 +9,10 @@ version_source: author: "Marat Fayzullin (Garage Research)" profiled_date: "2026-10-20" core_version: "5.9.13" +version_basis: + kind: package + url: "https://play.google.com/store/apps/details?id=com.fms.speccy" + artifact: "com.fms.speccy APK versionName (versionCode 5913)" display_name: "Sinclair - ZX Spectrum and Sam Coupe (Speccy)" verification: existence cores: diff --git a/emulators/splitwolf.yml b/emulators/splitwolf.yml index 6c002829f..e5e3d699b 100644 --- a/emulators/splitwolf.yml +++ b/emulators/splitwolf.yml @@ -6,6 +6,9 @@ source_branch: scrubbed profiled_date: "2026-10-20" source_commit: "f6c00044cdef00a31c66307d8b7cb1fb4ddf8c67" core_version: "V1.01" +version_basis: + kind: unverified + why: host_unsupported display_name: "Wolfenstein 3D (SplitWolf)" cores: [splitwolf] systems: [wolfenstein3d] diff --git a/emulators/spmp8000emu.yml b/emulators/spmp8000emu.yml index d61d7f961..7244cf773 100644 --- a/emulators/spmp8000emu.yml +++ b/emulators/spmp8000emu.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/AloysHF/SPMP8000Emu" profiled_date: "2026-09-03" source_commit: "65a93528ee33767bb9cf8faef516c8d1ad43fd13" core_version: "1.0.0" +version_basis: + kind: file + path: "Cargo.toml" + pattern: 'version\s+=\s+"([^"]+)' display_name: "Sunplus - SPMP8000 (SPMP8000Emu)" cores: - spmp8000emu diff --git a/emulators/squirreljme.yml b/emulators/squirreljme.yml index 2d7ef8a25..729338e2f 100644 --- a/emulators/squirreljme.yml +++ b/emulators/squirreljme.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/SquirrelJME/SquirrelJME" profiled_date: "2026-03-25" source_commit: "24d0e97d4297d0bce26a9651f5bce5d326ea690a" core_version: "0.3.0" +version_basis: + kind: file + path: "squirreljme-version" + pattern: '^([0-9][^\s]*)' display_name: "Java ME (SquirrelJME)" cores: [squirreljme] systems: [j2me] diff --git a/emulators/srb2.yml b/emulators/srb2.yml index 4079f6ea5..83efa5aab 100644 --- a/emulators/srb2.yml +++ b/emulators/srb2.yml @@ -6,6 +6,10 @@ upstream: "https://git.do.srb2.org/STJr/SRB2" profiled_date: "2026-10-20" source_commit: "639b58c6d718452ef343a0bc927d043bed9e40d6" core_version: "2.2.15" +version_basis: + kind: file + path: "src/version.h" + pattern: '#define\s+SRB2VERSION\s+"([^"]+)' display_name: "Sonic Robo Blast 2" cores: [srb2] systems: [] diff --git a/emulators/ssf.yml b/emulators/ssf.yml index b0dde7a5a..86a83c144 100644 --- a/emulators/ssf.yml +++ b/emulators/ssf.yml @@ -7,6 +7,12 @@ author: "Shima" profiled_date: "2026-08-12" source_commit: "432e257c312f705d5f85f298710d152240111da8" core_version: "PreviewVer R38" +version_basis: + kind: package + url: "https://github.com/shimazzz/SEGASaturnEmulator-SSF/releases/download/PreviewVer/SSF_PreviewVer_R38.zip" + pattern: 'SSF_(PreviewVer)_(R\d+)\.zip' + format: "{1} {2}" + artifact: "SSF_PreviewVer_R38.zip" display_name: "Sega - Saturn/ST-V (SSF)" cores: - ssf diff --git a/emulators/starboard.yml b/emulators/starboard.yml index 3e858b2bd..912f7c94a 100644 --- a/emulators/starboard.yml +++ b/emulators/starboard.yml @@ -7,6 +7,11 @@ author: "force9" profiled_date: "2026-10-27" source_commit: "d3a21a9aaeabb90e59d7a48241b293dba3ee9309" core_version: "0.40.0" +version_basis: + kind: package + url: "https://github.com/get-starboard/starboard/releases/download/v0.40.0/Starboard-v0.40.0.apk" + pattern: 'Starboard-v([0-9][0-9.]*[0-9])\.apk' + artifact: "Starboard-v0.40.0.apk" display_name: "PortMaster library (Starboard)" verification: existence cores: diff --git a/emulators/starship.yml b/emulators/starship.yml index a8e1c9154..430796830 100644 --- a/emulators/starship.yml +++ b/emulators/starship.yml @@ -5,7 +5,11 @@ source: "https://github.com/HarbourMasters/Starship" upstream: "https://github.com/HarbourMasters/Starship" source_commit: "cb19785b51698185a688e17ba1a34c7889195bdb" profiled_date: "2026-10-20" -core_version: "2.0.0" +core_version: "v2.0.0" +version_basis: + kind: tag + tag: "v2.0.0" + distance: 0 display_name: "Star Fox 64 (Starship)" cores: [starship] systems: [starship] diff --git a/emulators/stella.yml b/emulators/stella.yml index 7d0baebe9..7031022c7 100644 --- a/emulators/stella.yml +++ b/emulators/stella.yml @@ -5,6 +5,10 @@ source: "https://github.com/stella-emu/stella" profiled_date: "2026-10-21" source_commit: "289a40f1b63022b8bbe5b722061c660009d5de2c" core_version: "8.0_pre" +version_basis: + kind: file + path: "src/common/Version.hxx" + pattern: 'STELLA_VERSION\s*=\s*"([^"]+)"' display_name: "Atari - 2600 (Stella)" library_name: "Stella" cores: diff --git a/emulators/stella2014.yml b/emulators/stella2014.yml index 1550543f2..bdc60c8e5 100644 --- a/emulators/stella2014.yml +++ b/emulators/stella2014.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-25" source_commit: "7d1361e407e63f29e52892655069e5fb4096e691" upstream_commit: "289a40f1b63022b8bbe5b722061c660009d5de2c" core_version: "3.9.3" +version_basis: + kind: file + path: "stella/src/common/Version.hxx" + pattern: '#define\s+STELLA_VERSION\s+"([^"]+)' display_name: "Atari - 2600 (Stella 2014)" cores: - stella2014 diff --git a/emulators/stella2023.yml b/emulators/stella2023.yml index 95b8d3200..edef189e5 100644 --- a/emulators/stella2023.yml +++ b/emulators/stella2023.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-25" source_commit: "ba52c43b9eda950eb0c0eec69cda9b17dee8c39b" upstream_commit: "408dd6a30cc6fd91decc602403281c7dcfbc1b82" core_version: "7.0_pre" +version_basis: + kind: file + path: "src/common/Version.hxx" + pattern: '#define\s+STELLA_VERSION\s+"([^"]+)' display_name: "Atari - 2600 (Stella 2023)" cores: - stella2023 diff --git a/emulators/stonesoup.yml b/emulators/stonesoup.yml index c51953275..2d4a86ce5 100644 --- a/emulators/stonesoup.yml +++ b/emulators/stonesoup.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-25" source_commit: "cc2530f377a3a5d686d4b6a360d88b01de0fbc59" upstream_commit: "a5ed93406571b9682050cfc318b15b9f637d4e7e" core_version: "0.16-a0" +version_basis: + kind: file + path: "crawl-ref/source/build.h" + pattern: '#define\s+CRAWL_VERSION_SHORT\s+"([^"]+)"' display_name: "Dungeon Crawl Stone Soup" cores: [stonesoup] systems: [] diff --git a/emulators/stratagus.yml b/emulators/stratagus.yml index feba5891d..acf53ab08 100644 --- a/emulators/stratagus.yml +++ b/emulators/stratagus.yml @@ -4,7 +4,11 @@ core_classification: game_engine source: "https://github.com/Wargus/stratagus" profiled_date: "2026-10-20" source_commit: "6b309817027618a12e26e4cf314ad09654495e28" -core_version: "2.4.3" +core_version: "v2.4.3" +version_basis: + kind: tag + tag: "v2.4.3" + distance: 0 display_name: "Stratagus" cores: [stratagus] systems: [] diff --git a/emulators/sudachi.yml b/emulators/sudachi.yml index 2604c85a0..5caf7834f 100644 --- a/emulators/sudachi.yml +++ b/emulators/sudachi.yml @@ -6,6 +6,9 @@ upstream_gone: "The emuplace GitHub account answers 404 and sudachi.emuplace.app profiled_date: "2026-10-20" source_commit: "c7431bd420d66c54df277ba0a0b71de42cf0a5bf" core_version: "1.0.15" +version_basis: + kind: unverified + why: host_gone display_name: "Sudachi (Nintendo Switch)" cores: - sudachi diff --git a/emulators/sugarbox2.yml b/emulators/sugarbox2.yml index 7cb7651b1..d0d5db1b6 100644 --- a/emulators/sugarbox2.yml +++ b/emulators/sugarbox2.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/Tom1975/SugarboxV2" profiled_date: "2026-10-17" source_commit: "6b565a43a25e4dfb69867f7e927a707e15ea460f" core_version: "v0.9" +version_basis: + kind: tag + tag: "v0.9" + distance: 0 display_name: "Amstrad - CPC / GX4000 (Sugarbox2)" cores: - "sugarbox2" diff --git a/emulators/super3.yml b/emulators/super3.yml index f2e40d0d4..1d0c01b7b 100644 --- a/emulators/super3.yml +++ b/emulators/super3.yml @@ -8,6 +8,10 @@ author: "izzy2lost" profiled_date: "2026-10-27" source_commit: "c410f82f771b33094b8c1cdbf96ef7c74ec9cff1" core_version: "1.2.2" +version_basis: + kind: tag + tag: "1.2.2" + distance: 0 display_name: "Sega - Model 3 (SUPER3)" verification: existence cores: diff --git a/emulators/superbroswar.yml b/emulators/superbroswar.yml index 974e3a722..bdefff39e 100644 --- a/emulators/superbroswar.yml +++ b/emulators/superbroswar.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/superbroswar-libretro" upstream: "https://github.com/mmatyas/supermariowar" profiled_date: "2026-03-25" source_commit: "7f94e03163e1641ecd2a5703eb9ca7e1312b5e8d" -core_version: "v0.1" +core_version: "0.1" +version_basis: + kind: file + path: "libretro/libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Super Bros War" cores: [superbroswar] systems: [] diff --git a/emulators/supermariowar.yml b/emulators/supermariowar.yml index 223faa533..d2ce65c99 100644 --- a/emulators/supermariowar.yml +++ b/emulators/supermariowar.yml @@ -6,6 +6,10 @@ profiled_date: "2026-10-22" source_commit: "ed60ed45e296ff88a8883cbc51f5bf5aed880636" pin_frozen: "EmuELEC, the only platform that ships it, builds this revision (EmuELEC packages/sx05re/emuelec-ports/supermariowar/package.mk:5). Later commits are not part of that build." core_version: "2.0.0" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'project\(smw\s+VERSION\s+([0-9][^\s)]*)' display_name: "Super Mario War (smw)" cores: - "smw" diff --git a/emulators/supermodel-dojo.yml b/emulators/supermodel-dojo.yml index 6ace9207c..2a8b3d8a5 100644 --- a/emulators/supermodel-dojo.yml +++ b/emulators/supermodel-dojo.yml @@ -9,6 +9,10 @@ source_commit: "113a48d567c5d49a40292df386fee4a0acaea486" upstream_commit: "98fcbff223e23b1530c8f899aca2fc4fd5663ab4" upstream_frozen: "The dojo branch merged trzy/Supermodel at this commit through merge ab1ecae. Later upstream commits are not in the port." core_version: "v0.3a-20261024-git-113a48d" +version_basis: + kind: tag + tag: "v0.3a-20261024-git-113a48d" + distance: 0 display_name: "Sega - Model 3 (Supermodel Dojo)" verification: existence cores: diff --git a/emulators/supermodel-legacy.yml b/emulators/supermodel-legacy.yml index 5dde17f5a..a501a3883 100644 --- a/emulators/supermodel-legacy.yml +++ b/emulators/supermodel-legacy.yml @@ -7,6 +7,10 @@ profiled_date: "2026-10-17" source_commit: "0eef09ba2b74e48fd5cfd388ee69a3743fd5f618" pin_frozen: "Batocera's supermodel-legacy package builds this revision, held before the renderer moved to OpenGL 4.1. Recaling would repoint these refs at code this build never had." core_version: "0.3a-WIP" +version_basis: + kind: file + path: "Src/Version.h" + pattern: '#define\s+SUPERMODEL_VERSION\s+"([^"]+)' display_name: "Sega - Model 3 (Supermodel Legacy)" cores: - "supermodel-legacy" diff --git a/emulators/supermodel.yml b/emulators/supermodel.yml index 120433931..7c5976c86 100644 --- a/emulators/supermodel.yml +++ b/emulators/supermodel.yml @@ -11,8 +11,17 @@ source_commit: libretro: "84bc106b45b279bf868a53b9232897c8dc10ca17" upstream_commit: "14815455dc28fca2c8662fb1ed99d447ecf8f364" core_version: - standalone: "0.3a-WIP" - libretro: "v0.3a-libretro" + standalone: "v0.3a-20261025-git-1481545" + libretro: "0.3a-WIP" +version_basis: + standalone: + kind: tag + tag: "v0.3a-20261025-git-1481545" + distance: 0 + libretro: + kind: file + path: "Src/Version.h" + pattern: '#define\s+SUPERMODEL_VERSION\s+"([^"]+)"' display_name: "Sega - Model 3 (Supermodel)" cores: - supermodel diff --git a/emulators/supermodel3.yml b/emulators/supermodel3.yml index d09fad631..aea86ea3a 100644 --- a/emulators/supermodel3.yml +++ b/emulators/supermodel3.yml @@ -10,6 +10,10 @@ prose_written_at: "11726c4bad3696a50a8b834eaba6aee3fa08a590" upstream_commit: "14815455dc28fca2c8662fb1ed99d447ecf8f364" upstream_frozen: "The fork is rebased on trzy's tree at 1481545, the revision its version string names. Later trzy commits are not in the fork." core_version: "0.3a-1481545-mm DirtBagXon (Sinden)" +version_basis: + kind: file + path: "Src/Version.h" + pattern: '#define\s+SUPERMODEL_VERSION\s+"([^"]+)' display_name: "Sega - Model 3 (Supermodel, Sinden fork)" verification: existence cores: diff --git a/emulators/supersnes9x.yml b/emulators/supersnes9x.yml index 9c123eca5..bb8966d61 100644 --- a/emulators/supersnes9x.yml +++ b/emulators/supersnes9x.yml @@ -7,6 +7,11 @@ profiled_date: "2026-10-17" source_commit: "691e47b40fb38fa522a5471462344a2f0206b7a8" pin_frozen: "ROCKNIX 20261001 builds this revision. Later commits on shanytc/snes9x rework the Super Famicom Box loader and are not part of that build." core_version: "1.63.29" +version_basis: + kind: file + path: "snes9x.h" + pattern: '#define\s+VERSION\s+"([^"]+)"\s*\n#define\s+PATCH_VERSION\s+"([^"]+)"' + format: "{1}.{2}" display_name: "Nintendo - SNES / SFC / SGB / GB / GBC (SuperSnes9x)" cores: - "supersnes9x" diff --git a/emulators/supertux.yml b/emulators/supertux.yml index eb42c76dd..c05f1b9d6 100644 --- a/emulators/supertux.yml +++ b/emulators/supertux.yml @@ -5,7 +5,12 @@ source: "https://github.com/SuperTux/supertux" profiled_date: "2026-10-22" source_commit: "37cddf24a4abfdec7931a84afd9e87fb8ea18767" pin_frozen: "EmuELEC, the only platform that ships it, builds this revision, v0.6.3 (EmuELEC packages/sx05re/emuelec-ports/supertux/package.mk:5). Later commits are not part of that build." -core_version: "0.6.3-1020-g37cddf24a" +core_version: "v0.6.3-1020-g37cddf2" +version_basis: + kind: tag + match: "?[0-9]*.[0-9]*.[0-9]*" + tag: "v0.6.3" + distance: 1020 display_name: "SuperTux (supertux2)" cores: - "supertux2" diff --git a/emulators/supertuxkart.yml b/emulators/supertuxkart.yml index 5701311e4..9fe306c0f 100644 --- a/emulators/supertuxkart.yml +++ b/emulators/supertuxkart.yml @@ -5,7 +5,11 @@ source: "https://github.com/supertuxkart/stk-code" profiled_date: "2026-10-22" source_commit: "fab79150111944c9e33396db68eb5de84f2efeaa" pin_frozen: "EmuELEC, the only platform that ships it, builds this revision (EmuELEC packages/sx05re/emuelec-ports/supertuxkart/package.mk:5). Later commits are not part of that build." -core_version: "git" +core_version: "preview-582-gfab7915" +version_basis: + kind: tag + tag: "preview" + distance: 582 display_name: "SuperTuxKart" cores: - "supertuxkart" diff --git a/emulators/superzsnes.yml b/emulators/superzsnes.yml index 0a60fad84..622381f47 100644 --- a/emulators/superzsnes.yml +++ b/emulators/superzsnes.yml @@ -8,6 +8,11 @@ version_source: pattern: 'Latest Release Notes \((v[0-9.]+[a-z]?)\)' profiled_date: "2026-10-20" core_version: "v0.320" +version_basis: + kind: package + url: "https://www.zsnes.com/files/SuperZSNES_v0.320.zip" + pattern: 'SuperZSNES_(v\d+\.\d+)\.zip' + artifact: "SuperZSNES_v0.320.zip" display_name: "Nintendo - SNES / SFC (SUPER ZSNES)" cores: - superzsnes diff --git a/emulators/suyu.yml b/emulators/suyu.yml index b5fe2f853..e95834d14 100644 --- a/emulators/suyu.yml +++ b/emulators/suyu.yml @@ -6,6 +6,9 @@ upstream: "https://github.com/suyu-emu/suyu" profiled_date: "2026-03-26" upstream_gone: "GitHub withdrew the repository for legal reasons: the API answers HTTP 451. git.suyu.dev still serves a Forgejo page, but its API answers 403 and its raw paths 404, so it carries no readable tree. Observed 2026-09-04." core_version: "Yuzu EA 4176 based" +version_basis: + kind: unverified + why: host_gone display_name: "Suyu (Nintendo Switch)" cores: - suyu diff --git a/emulators/swan-emu.yml b/emulators/swan-emu.yml index 74f8823d6..16c1187ef 100644 --- a/emulators/swan-emu.yml +++ b/emulators/swan-emu.yml @@ -6,6 +6,10 @@ upstream: "https://mednafen.github.io/" profiled_date: "2026-08-12" source_commit: "1c12fac5ce49badaadff2e2f210dcc30b89f4943" core_version: "1.5.85" +version_basis: + kind: file + path: "EmuFramework/metadata/conf.mk" + pattern: '^metadata_version\s*=\s*(\S+)' display_name: "Bandai - WonderSwan / Color (Swan.emu)" mode: standalone cores: diff --git a/emulators/swanstation.yml b/emulators/swanstation.yml index 7887ad782..9db5fa669 100644 --- a/emulators/swanstation.yml +++ b/emulators/swanstation.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/stenzek/duckstation" profiled_date: "2026-03-25" source_commit: "631f0fb31b809e0f889d7c551fe695788e39c1d3" upstream_commit: "526b4a128827ecaef037134095cd95f431b52d06" -core_version: "v0.1" +core_version: "1.0.0" +version_basis: + kind: file + path: "src/libretro/libretro_host_interface.cpp" + pattern: 'library_version\s*=\s*"([0-9][^" ]*)' display_name: "Sony - PlayStation (SwanStation)" cores: [swanstation] found_by: content diff --git a/emulators/swf-player.yml b/emulators/swf-player.yml index 3fcc56951..f71f6d1d2 100644 --- a/emulators/swf-player.yml +++ b/emulators/swf-player.yml @@ -9,6 +9,10 @@ version_source: author: "issess.net" profiled_date: "2026-08-12" core_version: "1.90 free (build 507)" +version_basis: + kind: package + url: "https://play.google.com/store/apps/details?id=com.issess.flashplayer" + artifact: "com.issess.flashplayer APK versionName (versionCode 507)" display_name: "Adobe Flash (SWF Player)" mode: standalone cores: diff --git a/emulators/syobonaction.yml b/emulators/syobonaction.yml index 5b64195e9..0df4bdace 100644 --- a/emulators/syobonaction.yml +++ b/emulators/syobonaction.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-25" source_commit: "792c40cb590bcc7286cf720b5fb85807082b534e" upstream_commit: "77ca2c128784512eca10e24a453ca19c270a8af4" core_version: "0.3" +version_basis: + kind: file + path: "libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Syobon Action" cores: [syobonaction] systems: [] diff --git a/emulators/tamalibretro.yml b/emulators/tamalibretro.yml index 3447ff1c9..39d5d7dad 100644 --- a/emulators/tamalibretro.yml +++ b/emulators/tamalibretro.yml @@ -6,7 +6,9 @@ upstream: "https://github.com/jcrona/tamalib" source_ref: "main.c:345-365 (retro_load_game)" profiled_date: "2026-03-25" source_commit: "ea8dd612eaab375a04f976149dc693cb5d208b27" -core_version: "1.0" +core_version: null +version_basis: + kind: none display_name: "Bandai - Tamagotchi P1 (TamaLIBretro)" cores: [tamalibretro] systems: [tamagotchi-p1] diff --git a/emulators/taradino.yml b/emulators/taradino.yml index 58640d580..be8621129 100644 --- a/emulators/taradino.yml +++ b/emulators/taradino.yml @@ -5,7 +5,11 @@ source: "https://github.com/fabiangreffrath/taradino" upstream: "https://github.com/fabiangreffrath/taradino" profiled_date: "2026-10-04" source_commit: "2b4ea3c6c18caf60959efee1f2534c2122607716" -core_version: "0.1" +core_version: "2025.12.22" +version_basis: + kind: file + path: "CMakeLists.txt" + pattern: 'project\(taradino[^)]*?\bVERSION\s+([0-9][0-9.]*)' display_name: "Taradino" cores: [taradino] systems: [rott] diff --git a/emulators/teknoparrot.yml b/emulators/teknoparrot.yml index 7403d1a51..2b2f4c0de 100644 --- a/emulators/teknoparrot.yml +++ b/emulators/teknoparrot.yml @@ -7,6 +7,9 @@ author: "TeknoGods" profiled_date: "2026-10-20" source_commit: "b75872addc1d5cce81a62f4c1468eab59e2d3cbe" core_version: "TeknoParrotUI 7ffcdf1" +version_basis: + kind: unverified + why: host_gone display_name: "Arcade - PC-based and Sega/Namco boards (TeknoParrot)" cores: - teknoparrot diff --git a/emulators/tempgba.yml b/emulators/tempgba.yml index 92386533e..719fdd3cb 100644 --- a/emulators/tempgba.yml +++ b/emulators/tempgba.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/Nebuleon/ReGBA" profiled_date: "2026-03-25" source_commit: "b0c2652797a4c11f3edd30f9e59a77a5b88ce5fb" core_version: "26731013" +version_basis: + kind: file + path: "libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Nintendo - Game Boy Advance (TempGBA)" cores: - tempgba diff --git a/emulators/test.yml b/emulators/test.yml index 29b8b9fff..7aa106683 100644 --- a/emulators/test.yml +++ b/emulators/test.yml @@ -4,7 +4,12 @@ core_classification: pure_libretro source: "https://github.com/libretro/libretro-samples" upstream: "https://github.com/libretro/libretro-samples" profiled_date: "2026-03-25" +source_commit: "bce193bc1b8c9a3da43b2ead0158a69e28b37ed8" core_version: "v1" +version_basis: + kind: file + path: "tests/test/libretro-test.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "Test" cores: - test diff --git a/emulators/test_netplay.yml b/emulators/test_netplay.yml index d671919d7..3319e5084 100644 --- a/emulators/test_netplay.yml +++ b/emulators/test_netplay.yml @@ -3,6 +3,9 @@ type: libretro core_classification: pure_libretro profiled_date: "2026-03-25" core_version: "1" +version_basis: + kind: unverified + why: no_source display_name: "Test for netplay" cores: - test_netplay diff --git a/emulators/testaudio_callback.yml b/emulators/testaudio_callback.yml index 776436799..7cf4184c5 100644 --- a/emulators/testaudio_callback.yml +++ b/emulators/testaudio_callback.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/libretro/libretro-samples" profiled_date: "2026-03-25" source_commit: "7c2ad112d7a5176de2191e473369668da8946b16" core_version: "v1" +version_basis: + kind: file + path: "audio/audio_callback/libretro-test.c" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "TestAudio Callback" cores: - testaudio_callback diff --git a/emulators/testaudio_no_callback.yml b/emulators/testaudio_no_callback.yml index 1141391a6..dd4796975 100644 --- a/emulators/testaudio_no_callback.yml +++ b/emulators/testaudio_no_callback.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/libretro/libretro-samples" profiled_date: "2026-03-25" source_commit: "7c2ad112d7a5176de2191e473369668da8946b16" core_version: "v1" +version_basis: + kind: file + path: "audio/audio_no_callback/libretro-test.c" + pattern: 'library_version\s*=\s*"([^"]+)"' display_name: "TestAudio NoCallback" cores: - testaudio_no_callback diff --git a/emulators/testaudio_playback_wav.yml b/emulators/testaudio_playback_wav.yml index 187ed91e3..e5cfcf963 100644 --- a/emulators/testaudio_playback_wav.yml +++ b/emulators/testaudio_playback_wav.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/libretro/libretro-samples" profiled_date: "2026-03-25" source_commit: "7c2ad112d7a5176de2191e473369668da8946b16" core_version: "v1" +version_basis: + kind: file + path: "audio/audio_playback_wav/libretro-test.c" + pattern: 'retro_system_info\s+myinfo\s*=\s*\{\s*"[^"]*",\s*"([^"]+)"' display_name: "TestAudio Playback Wav" cores: - testaudio_playback_wav diff --git a/emulators/testgl.yml b/emulators/testgl.yml index ec10faf45..2c0d9a58c 100644 --- a/emulators/testgl.yml +++ b/emulators/testgl.yml @@ -4,7 +4,12 @@ core_classification: pure_libretro source: "https://github.com/libretro/libretro-samples" upstream: "https://github.com/libretro/libretro-samples" profiled_date: "2026-03-25" +source_commit: "bce193bc1b8c9a3da43b2ead0158a69e28b37ed8" core_version: "v1" +version_basis: + kind: file + path: "video/opengl/libretro_test_gl_shaders/libretro_gl_test.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "TestGL" cores: - testgl diff --git a/emulators/testgl_compute_shaders.yml b/emulators/testgl_compute_shaders.yml index 30b823139..60db79d38 100644 --- a/emulators/testgl_compute_shaders.yml +++ b/emulators/testgl_compute_shaders.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/libretro/libretro-samples" profiled_date: "2026-03-25" source_commit: "7c2ad112d7a5176de2191e473369668da8946b16" core_version: "v1" +version_basis: + kind: file + path: "video/opengl/libretro_test_gl_compute_shaders/app/boxes.cpp" + pattern: 'info\.library_version\s*=\s*"([^"]+)"' display_name: "TestGL ComputeShaders" cores: - testgl_compute_shaders diff --git a/emulators/testgl_ff.yml b/emulators/testgl_ff.yml index 21ad2d7f9..889d7fc7c 100644 --- a/emulators/testgl_ff.yml +++ b/emulators/testgl_ff.yml @@ -7,6 +7,10 @@ source_ref: "video/opengl/libretro_test_gl_fixedfunction/libretro_gl_ff_test.c" profiled_date: "2026-03-25" source_commit: "7c2ad112d7a5176de2191e473369668da8946b16" core_version: "v1" +version_basis: + kind: file + path: "video/opengl/libretro_test_gl_fixedfunction/libretro_gl_ff_test.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "TestGL (FF)" cores: - testgl_ff diff --git a/emulators/testinput_buttontest.yml b/emulators/testinput_buttontest.yml index 2be09c874..5c060eb7e 100644 --- a/emulators/testinput_buttontest.yml +++ b/emulators/testinput_buttontest.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/libretro-samples" upstream: "https://github.com/libretro/libretro-samples" profiled_date: "2026-03-25" source_commit: "7c2ad112d7a5176de2191e473369668da8946b16" -core_version: "v1" +core_version: "0.01" +version_basis: + kind: file + path: "input/button_test/libretro.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "Button Test" cores: - testinput_buttontest diff --git a/emulators/testretroluxury.yml b/emulators/testretroluxury.yml index 99e3da0c7..4a6a91e18 100644 --- a/emulators/testretroluxury.yml +++ b/emulators/testretroluxury.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/retroluxury" upstream: "https://github.com/leiradel/retroluxury" profiled_date: "2026-03-25" source_commit: "fdcd94fe4099735edcbea638760da3f2297bc520" -core_version: "v1" +core_version: "0.1" +version_basis: + kind: file + path: "test/libretro.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "Test RetroLuxury" cores: - testretroluxury diff --git a/emulators/testsw.yml b/emulators/testsw.yml index 672062ada..b80427c05 100644 --- a/emulators/testsw.yml +++ b/emulators/testsw.yml @@ -7,6 +7,10 @@ upstream: null profiled_date: "2026-03-25" source_commit: "7c2ad112d7a5176de2191e473369668da8946b16" core_version: "v1" +version_basis: + kind: file + path: "video/software/rendering/libretro-test.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "TestSW" cores: - testsw diff --git a/emulators/testsw_vram.yml b/emulators/testsw_vram.yml index be0836cd2..dd461b1a9 100644 --- a/emulators/testsw_vram.yml +++ b/emulators/testsw_vram.yml @@ -7,6 +7,10 @@ source_ref: "video/software/rendering_direct_to_vram/libretro-test.c" profiled_date: "2026-03-25" source_commit: "7c2ad112d7a5176de2191e473369668da8946b16" core_version: "v1" +version_basis: + kind: file + path: "video/software/rendering_direct_to_vram/libretro-test.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "TestSW VRAM" cores: - testsw_vram diff --git a/emulators/testvulkan.yml b/emulators/testvulkan.yml index 66fbcf55e..bdfa9d66c 100644 --- a/emulators/testvulkan.yml +++ b/emulators/testvulkan.yml @@ -4,7 +4,12 @@ core_classification: pure_libretro source: "https://github.com/libretro/libretro-samples" upstream: "https://github.com/libretro/libretro-samples" profiled_date: "2026-03-25" +source_commit: "bce193bc1b8c9a3da43b2ead0158a69e28b37ed8" core_version: "v1" +version_basis: + kind: file + path: "video/vulkan/vk_rendering/libretro-test.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "TestVulkan" cores: - testvulkan diff --git a/emulators/testvulkan_async_compute.yml b/emulators/testvulkan_async_compute.yml index bf169fa3a..fcf630031 100644 --- a/emulators/testvulkan_async_compute.yml +++ b/emulators/testvulkan_async_compute.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/libretro/libretro-samples" profiled_date: "2026-03-25" source_commit: "7c2ad112d7a5176de2191e473369668da8946b16" core_version: "v1" +version_basis: + kind: file + path: "video/vulkan/vk_async_compute/libretro-test.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "TestVulkan AsyncCompute" cores: - testvulkan_async_compute diff --git a/emulators/tgbdual.yml b/emulators/tgbdual.yml index 4e1e64299..42c28bc58 100644 --- a/emulators/tgbdual.yml +++ b/emulators/tgbdual.yml @@ -6,6 +6,10 @@ upstream: "http://gigo.retrogames.com/download.html#tgb-dual" profiled_date: "2026-03-25" source_commit: "0392c9c469e653205e471114c7949c07c83bfce9" core_version: "v0.8.3" +version_basis: + kind: file + path: "libretro/libretro.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Nintendo - Game Boy / Color (TGB Dual)" cores: - TGB Dual diff --git a/emulators/theforceengine.yml b/emulators/theforceengine.yml index 2b3838da9..073e34f48 100644 --- a/emulators/theforceengine.yml +++ b/emulators/theforceengine.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/TheForceEngine/TheForceEngine" profiled_date: "2026-10-04" source_commit: "cc25205cc94c36a396f6f50295772f6ec83069a2" core_version: "v1.22.420" +version_basis: + kind: tag + tag: "v1.22.420" + distance: 0 display_name: "The Force Engine" cores: [theforceengine, tfe] systems: [dark-forces, outlaws] diff --git a/emulators/theodore.yml b/emulators/theodore.yml index b89062f77..7fa061199 100644 --- a/emulators/theodore.yml +++ b/emulators/theodore.yml @@ -5,7 +5,11 @@ source: "https://github.com/Zlika/theodore" upstream: "http://dcmoto.free.fr/" profiled_date: "2026-03-25" source_commit: "4d469ce0f71ee046ceb78cdbf8e9f18364aaa918" -core_version: "Git (post-3.1)" +core_version: "v3.2-9-g4d469ce" +version_basis: + kind: tag + tag: "v3.2" + distance: 9 display_name: "Thomson - MO/TO (Theodore)" cores: [theodore] systems: [thomson-to7, thomson-to770, thomson-to8, thomson-to8d, thomson-to9, thomson-to9plus, thomson-mo5, thomson-mo6, olivetti-pc128] diff --git a/emulators/thepowdertoy.yml b/emulators/thepowdertoy.yml index b1873d68f..3d61c3356 100644 --- a/emulators/thepowdertoy.yml +++ b/emulators/thepowdertoy.yml @@ -5,7 +5,12 @@ source: "https://github.com/libretro/ThePowderToy" upstream: "https://github.com/The-Powder-Toy/The-Powder-Toy" profiled_date: "2026-03-25" source_commit: "bb2d9f6623d2ccf25a0021045af9591c8a0bbaff" -core_version: "v92.5.336" +core_version: "92.5.336" +version_basis: + kind: file + path: "src/Config.h" + pattern: '#define SAVE_VERSION (\d+)[\s\S]*?#define MINOR_VERSION (\d+)[\s\S]*?#define BUILD_NUM (\d+)' + format: "{1}.{2}.{3}" display_name: "The Powder Toy" cores: [thepowdertoy] systems: [] diff --git a/emulators/thextech.yml b/emulators/thextech.yml index 185e99ef1..5a7844b7a 100644 --- a/emulators/thextech.yml +++ b/emulators/thextech.yml @@ -5,6 +5,11 @@ source: "https://github.com/TheXTech/TheXTech" upstream: "https://github.com/TheXTech/TheXTech" profiled_date: "2026-10-04" source_commit: "e07c5bfb92377d315d0ab33177092fa7cadeb84e" +core_version: "1.8-dev" +version_basis: + kind: file + path: "version.cmake" + pattern: 'set\(THEXTECH_ANDROID_VERSION_NAME "([^"]+)"\)' display_name: "TheXTech" cores: [] systems: [smbx] diff --git a/emulators/ti99sim-sdl1.yml b/emulators/ti99sim-sdl1.yml index c1219c58d..563f92548 100644 --- a/emulators/ti99sim-sdl1.yml +++ b/emulators/ti99sim-sdl1.yml @@ -6,6 +6,11 @@ source: "https://files.retropie.org.uk/archives/ti99sim-0.15.0.src.tar.gz" upstream: "https://www.mrousseau.org/programs/ti99sim/" profiled_date: "2026-10-20" core_version: "0.15.0" +version_basis: + kind: package + url: "https://files.retropie.org.uk/archives/ti99sim-0.15.0.src.tar.gz" + pattern: 'ti99sim-(\d+\.\d+\.\d+)\.src\.tar\.gz' + artifact: "ti99sim-0.15.0.src.tar.gz" cores: - ti99sim-sdl1 systems: diff --git a/emulators/ti99sim.yml b/emulators/ti99sim.yml index a2f391be6..1d6d11c6b 100644 --- a/emulators/ti99sim.yml +++ b/emulators/ti99sim.yml @@ -5,7 +5,9 @@ source: https://github.com/christianhaitian/ti99sim upstream: https://www.mrousseau.org/programs/ti99sim/ profiled_date: "2026-03-29" source_commit: "e3608541943b5258afe45b74e3f78e723df1fcbd" -core_version: "0.16.0" +core_version: null +version_basis: + kind: none cores: - ti99sim diff --git a/emulators/tia.yml b/emulators/tia.yml index 04289ad16..04570070a 100644 --- a/emulators/tia.yml +++ b/emulators/tia.yml @@ -5,7 +5,9 @@ source: "https://github.com/warmenhoven/tia" upstream: "https://github.com/warmenhoven/tia" profiled_date: "2026-09-03" source_commit: "6ae5bf998fe7a7842294089db17fc86fd73db1f0" -core_version: "52+6ae5bf9" +core_version: null +version_basis: + kind: none display_name: "Atari - 2600 (Tia)" cores: - tia diff --git a/emulators/tic80.yml b/emulators/tic80.yml index 3f2491049..6252f0505 100644 --- a/emulators/tic80.yml +++ b/emulators/tic80.yml @@ -6,7 +6,13 @@ upstream: "https://github.com/nesbox/TIC-80" profiled_date: "2026-03-25" source_commit: "14fd99edc29962778bc88d81773288ffc6e8aa53" upstream_commit: "ae1195a9d0fbda243bf0ebd861d6876d072a979e" -core_version: "0.80.0" +core_version: "1.2.0-dev" +version_basis: + kind: file + repo: upstream + path: "cmake/version.cmake" + pattern: 'set\(VERSION_MAJOR (\d+)\)\s*set\(VERSION_MINOR (\d+)\)\s*set\(VERSION_REVISION (\d+)\)\s*set\(VERSION_STATUS "([^"]*)"\)' + format: "{1}.{2}.{3}{4}" display_name: "TIC-80" cores: - tic80 diff --git a/emulators/touchhle.yml b/emulators/touchhle.yml index 9c03a91ba..d588e5190 100644 --- a/emulators/touchhle.yml +++ b/emulators/touchhle.yml @@ -6,6 +6,10 @@ profiled_date: "2026-10-17" source_commit: "3c5850585ba55615b17a58c58331b6d6f52d4a9d" pin_frozen: "ROCKNIX 20261001 builds this revision. Later upstream commits are not part of that build." core_version: "0.2.3" +version_basis: + kind: file + path: "Cargo.toml" + pattern: 'version\s+=\s+"([^"]+)' display_name: "Apple - iPhone OS (touchHLE)" cores: - "touchhle" diff --git a/emulators/tr1x.yml b/emulators/tr1x.yml index eb91cfa9d..f39b7237e 100644 --- a/emulators/tr1x.yml +++ b/emulators/tr1x.yml @@ -6,6 +6,12 @@ source: "https://github.com/LostArtefacts/TRX" upstream: "https://github.com/LostArtefacts/TRX" source_commit: "4d55f7d3130f9d04bdc1fefb85bf4d8fa93a22d3" upstream_commit: "3d39911a1b839c753b6efad236db67d9fb2b273e" +core_version: "trx-1.11.1-784-g4d55f7d" +version_basis: + kind: tag + match: "trx-*" + tag: "trx-1.11.1" + distance: 784 profiled_date: "2026-10-04" cores: [] systems: diff --git a/emulators/tr2x.yml b/emulators/tr2x.yml index d11bd7717..93fb7238a 100644 --- a/emulators/tr2x.yml +++ b/emulators/tr2x.yml @@ -6,6 +6,12 @@ source: "https://github.com/LostArtefacts/TRX" upstream: "https://github.com/LostArtefacts/TRX" source_commit: "4d55f7d3130f9d04bdc1fefb85bf4d8fa93a22d3" upstream_commit: "3d39911a1b839c753b6efad236db67d9fb2b273e" +core_version: "trx-1.11.1-784-g4d55f7d" +version_basis: + kind: tag + match: "trx-*" + tag: "trx-1.11.1" + distance: 784 profiled_date: "2026-10-23" cores: [] systems: diff --git a/emulators/trident.yml b/emulators/trident.yml index 8c726b18d..63b6d0e49 100644 --- a/emulators/trident.yml +++ b/emulators/trident.yml @@ -7,7 +7,12 @@ upstream: https://github.com/DanAlexMorton/Panda3DS profiled_date: "2026-03-25" source_commit: "b97b0befa326105e181838bc6fa11c546de8294d" upstream_commit: "69095ee6d68d21eacac8d1517f0b7b4ed27884d3" -core_version: git +core_version: "v0.9-202-g69095ee" +version_basis: + kind: tag + repo: upstream + tag: "v0.9" + distance: 202 library_name: "Trident" cores: diff --git a/emulators/triforce.yml b/emulators/triforce.yml index 2e1f032a7..f5545d352 100644 --- a/emulators/triforce.yml +++ b/emulators/triforce.yml @@ -7,6 +7,11 @@ profiled_date: "2026-08-08" source_commit: "5c456e8ff0da0235be2cf1d55ba7bb2115b0cae2" upstream_commit: "b92e354389bb7c0bd114a8631b8af110d3cb3a14" core_version: "2407" +version_basis: + kind: tag + repo: upstream + tag: "2407" + distance: 0 display_name: "Namco / Sega / Nintendo - Triforce (Dolphin Triforce)" cores: - triforce diff --git a/emulators/tsugaru.yml b/emulators/tsugaru.yml index f66e7c981..b42da7acf 100644 --- a/emulators/tsugaru.yml +++ b/emulators/tsugaru.yml @@ -5,6 +5,11 @@ source: "https://github.com/captainys/TOWNSEMU" upstream: "https://github.com/captainys/TOWNSEMU" profiled_date: "2026-03-26" source_commit: "e27adde120fe06150f3d57a6dc7cba66b5f43a32" +core_version: "v20260522-179-ge27adde" +version_basis: + kind: tag + tag: "v20260522" + distance: 179 cores: - tsugaru systems: diff --git a/emulators/tyrquake.yml b/emulators/tyrquake.yml index 11f05a77d..9d60df008 100644 --- a/emulators/tyrquake.yml +++ b/emulators/tyrquake.yml @@ -6,6 +6,11 @@ upstream: "http://disenchant.net/tyrquake/" profiled_date: "2026-03-25" source_commit: "67db338ff4d27fdbcead61d4e54938d758ae62cb" core_version: "v0.62" +version_basis: + kind: file + path: "Makefile" + pattern: "-DTYR_VERSION=([0-9.]+)" + format: "v{1}" display_name: "Quake (TyrQuake)" cores: [tyrquake] systems: [quake] diff --git a/emulators/uae4all-rpi.yml b/emulators/uae4all-rpi.yml index 50af2fddd..cae0f03ae 100644 --- a/emulators/uae4all-rpi.yml +++ b/emulators/uae4all-rpi.yml @@ -7,6 +7,10 @@ source: "https://github.com/Chips-fr/uae4all-rpi" profiled_date: "2026-10-20" source_commit: "ae7eb74cfbe726a45f5b791484948676dcba1aef" core_version: "0.7" +version_basis: + kind: file + path: "libretro/core/libretro-core.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Commodore - Amiga (UAE4ALL)" systems: - commodore-amiga diff --git a/emulators/uae4all.yml b/emulators/uae4all.yml index dc5adad66..739c6bd9f 100644 --- a/emulators/uae4all.yml +++ b/emulators/uae4all.yml @@ -8,6 +8,10 @@ profiled_date: "2026-10-20" source_commit: "5c514dd6d8bb374bd22e2ee423bad99539207cbd" upstream_commit: "0f919a32b6d41a04cbc766c0e6076cda9fa7a63b" core_version: "2.3.6.2" +version_basis: + kind: file + path: "AndroidAppSettings.cfg" + pattern: '^AppVersionName="([^"]+)"' display_name: "Commodore - Amiga (UAE4All2)" cores: [uae4all] systems: [commodore-amiga] diff --git a/emulators/uae4arm.yml b/emulators/uae4arm.yml index bdd5ec8f5..ed7a4b19f 100644 --- a/emulators/uae4arm.yml +++ b/emulators/uae4arm.yml @@ -7,7 +7,11 @@ upstream: "https://github.com/PandTomB/uae4arm" profiled_date: "2026-03-25" source_commit: "26f444f01771f0dfa2fa652906ff8222e92e476e" upstream_commit: "161ddbaafe90a9747e9fb9c65ee4f38c163f335e" -core_version: "v0.5" +core_version: "0.5" +version_basis: + kind: file + path: "libretro/core/libretro-core.cpp" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Commodore - Amiga (UAE4ARM)" systems: - commodore-amiga diff --git a/emulators/ume2015.yml b/emulators/ume2015.yml index 70c94b7f9..20944e596 100644 --- a/emulators/ume2015.yml +++ b/emulators/ume2015.yml @@ -8,6 +8,10 @@ profiled_date: "2026-03-25" source_commit: "7adbf440d5f554097f58f8c6ebb673adc4320a31" upstream_commit: "6ae44e46f91aa2bd74d9895e6bfd345baebd3d22" core_version: "0.159" +version_basis: + kind: file + path: "src/version.c" + pattern: '#define\s+BARE_BUILD_VERSION\s+"([^"]+)' display_name: "Multi (UME 2015)" mame_version: "0.159" diff --git a/emulators/uqm.yml b/emulators/uqm.yml index 42de16372..a632b9547 100644 --- a/emulators/uqm.yml +++ b/emulators/uqm.yml @@ -6,6 +6,11 @@ upstream: "https://sourceforge.net/projects/sc2/" profiled_date: "2026-10-04" source_commit: "ff2444088d42e80612fd28f79d368783e244a606" core_version: "0.8.0" +version_basis: + kind: file + path: "sc2/src/uqmversion.h" + pattern: '#define UQM_MAJOR_VERSION_S\s+"(\d+)"[\s\S]*?#define UQM_MINOR_VERSION_S\s+"(\d+)"[\s\S]*?#define UQM_PATCH_VERSION_S\s+"(\d+)"[\s\S]*?#define UQM_EXTRA_VERSION\s+"([^"]*)"' + format: "{1}.{2}.{3}{4}" display_name: "The Ur-Quan Masters" cores: [uqm] systems: [ur-quan-masters, star-control-2] diff --git a/emulators/uw8.yml b/emulators/uw8.yml index 60f5276c4..f86c9c5b6 100644 --- a/emulators/uw8.yml +++ b/emulators/uw8.yml @@ -2,6 +2,10 @@ emulator: MicroW8 profiled_date: "2026-03-25" source_commit: "1a64f4bde9662cb3dc04214d2b9f8ead19c85f0a" core_version: "0.2.2" +version_basis: + kind: file + path: "uw8.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "MicroW8" type: libretro core_classification: pure_libretro diff --git a/emulators/uxn.yml b/emulators/uxn.yml index 506d3f3ab..0a4c28fc8 100644 --- a/emulators/uxn.yml +++ b/emulators/uxn.yml @@ -5,7 +5,11 @@ source: "https://codeberg.org/iyzsong/uxn-libretro" upstream: "https://github.com/chmod222/zuxn" profiled_date: "2026-03-25" source_commit: "2037b34ee0bf5f3914c38e0aafd145ece170b0f6" -core_version: "0.0.1" +core_version: "0.0.2" +version_basis: + kind: file + path: "build.zig.zon" + pattern: '^\s*\.version\s*=\s*"([^"]+)"' display_name: "Uxn / Varvara (zuxn)" cores: [uxn] systems: [] diff --git a/emulators/uzdoom.yml b/emulators/uzdoom.yml index 9fce74fa3..3d44c59b1 100644 --- a/emulators/uzdoom.yml +++ b/emulators/uzdoom.yml @@ -5,6 +5,10 @@ source: "https://github.com/UZDoom/UZDoom" profiled_date: "2026-10-20" source_commit: "7910df7102033fd7754a317f3254f24101135926" core_version: "5.0.3" +version_basis: + kind: tag + tag: "5.0.3" + distance: 0 display_name: "UZDoom" cores: - uzdoom diff --git a/emulators/uzem.yml b/emulators/uzem.yml index 38b5409a2..490c4dce5 100644 --- a/emulators/uzem.yml +++ b/emulators/uzem.yml @@ -7,6 +7,10 @@ profiled_date: "2026-03-25" source_commit: "d991ee94547c8294abc1c4cb73d63116aa58b5bc" upstream_commit: "eb02e5f69212983e778a2ca87b198f22071303b8" core_version: "v2.0" +version_basis: + kind: file + path: "uzem.h" + pattern: '#define\s+VERSION\s+"([^"]+)' display_name: "Uzebox (Uzem)" cores: - uzem diff --git a/emulators/vaporspec.yml b/emulators/vaporspec.yml index 7f4599af5..f68f0ca9f 100644 --- a/emulators/vaporspec.yml +++ b/emulators/vaporspec.yml @@ -5,7 +5,11 @@ source: "https://github.com/minkcv/vm" upstream: "https://github.com/minkcv/vm" profiled_date: "2026-03-25" source_commit: "11f63848a592644722ea1240b4b96785db9b009f" -core_version: "GIT" +core_version: "1.0" +version_basis: + kind: file + path: "machine/libretro.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "VaporSpec" cores: [vaporspec] systems: [vaporspec] diff --git a/emulators/vba_m.yml b/emulators/vba_m.yml index 921b7ebd3..61ee98ff9 100644 --- a/emulators/vba_m.yml +++ b/emulators/vba_m.yml @@ -1,5 +1,9 @@ emulator: VBA-M type: alias alias_of: vbam +core_version: "2.1.3" +version_basis: + kind: alias + of: "vbam" note: Legacy profile key retained for platform and buildbot compatibility. files: [] diff --git a/emulators/vba_next.yml b/emulators/vba_next.yml index 1c7306f2c..be3b6a07a 100644 --- a/emulators/vba_next.yml +++ b/emulators/vba_next.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/visualboyadvance-m/visualboyadvance-m" upstream_commit: "46cc9f6bda114737e99304a4bd8427c038e63084" profiled_date: "2026-03-25" source_commit: "788192f215ad0a1413f1625b40ebba3423fa0ade" -core_version: "SVN" +core_version: "v1.0.2" +version_basis: + kind: file + path: "libretro/libretro.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "Nintendo - Game Boy Advance (VBA Next)" cores: - vba_next diff --git a/emulators/vbam.yml b/emulators/vbam.yml index 3ff472c34..bc7d0ec5d 100644 --- a/emulators/vbam.yml +++ b/emulators/vbam.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/visualboyadvance-m/visualboyadvance-m" profiled_date: "2026-03-25" source_commit: "115defb3a318258ab84746d45258a1aec19d0b4b" upstream_commit: "46cc9f6bda114737e99304a4bd8427c038e63084" -core_version: "2.1.4" +core_version: "2.1.3" +version_basis: + kind: file + path: "CHANGELOG.md" + pattern: '^## +\[([0-9][^\]]*)\]' display_name: "Nintendo - Game Boy Advance (VBA-M)" cores: - vbam diff --git a/emulators/vecx.yml b/emulators/vecx.yml index c00e7cf7a..baaec255f 100644 --- a/emulators/vecx.yml +++ b/emulators/vecx.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/libretro-vecx" upstream: "https://github.com/jhawthorn/vecx" profiled_date: "2026-03-25" source_commit: "dccff5402a16d1ea7c112095a8e42632bf149506" -core_version: "SVN" +core_version: "1.2" +version_basis: + kind: file + path: "libretro.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "GCE - Vectrex (vecx)" cores: - vecx diff --git a/emulators/veesem.yml b/emulators/veesem.yml index 57abbf5ef..d97a725a5 100644 --- a/emulators/veesem.yml +++ b/emulators/veesem.yml @@ -5,7 +5,11 @@ source: "https://github.com/sp1187/veesem" upstream: "https://github.com/sp1187/veesem" profiled_date: "2026-08-08" source_commit: "42fb8f07e7418f16ccfb7364127aef2217dda641" -core_version: "0.2" +core_version: "v0.2" +version_basis: + kind: tag + tag: "v0.2" + distance: 0 display_name: "VTech - V.Smile (veesem)" cores: - veesem diff --git a/emulators/vemulator.yml b/emulators/vemulator.yml index dee7a02d7..781b6c3cc 100644 --- a/emulators/vemulator.yml +++ b/emulators/vemulator.yml @@ -6,6 +6,10 @@ upstream: "closed-source Android app (removed from Google Play ~2020)" profiled_date: "2026-03-25" source_commit: "27a062f6ae532e5028e4fb54f523cc689e78146a" core_version: "0.1" +version_basis: + kind: file + path: "main.cpp" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "VeMUlator" cores: - vemulator diff --git a/emulators/vice-standalone.yml b/emulators/vice-standalone.yml index cacd11daf..612ac8f1f 100644 --- a/emulators/vice-standalone.yml +++ b/emulators/vice-standalone.yml @@ -8,6 +8,11 @@ profiled_date: "2026-10-24" source_commit: "81546e60c222fe4aef750b890b0dbe3a5ac280d8" pin_frozen: "ROCKNIX, the only platform that ships it, builds this revision (ROCKNIX projects/ROCKNIX/packages/emulators/standalone/vice-sa/package.mk:5). Later commits are not part of that build." core_version: "3.8" +version_basis: + kind: file + path: "vice/configure.ac" + pattern: 'm4_define\(vice_version_major, (\d+)\)\s*m4_define\(vice_version_minor, (\d+)\)\s*m4_define\(vice_version_build, 0\)' + format: "{1}.{2}" display_name: "Commodore - 8-bit computers (VICE SDL2)" mode: standalone cores: diff --git a/emulators/vice.yml b/emulators/vice.yml index 3c13c4c44..891baeef5 100644 --- a/emulators/vice.yml +++ b/emulators/vice.yml @@ -15,7 +15,11 @@ source: "https://github.com/libretro/vice-libretro" logo: "https://raw.githubusercontent.com/VICE-Team/svn-mirror/main/vice/data/common/vice-logo-black.svg" profiled_date: "2026-03-18" source_commit: "6cbc44add8b0a03791b343712dc63dc1edad2675" -core_version: "3.9" +core_version: "3.10" +version_basis: + kind: file + path: "vice/configure" + pattern: '^VICE_VERSION=(\S+)' display_name: "Commodore - C64 (VICE x64, fast)" systems: - commodore-c64 diff --git a/emulators/vice_x128.yml b/emulators/vice_x128.yml index c07198f9d..934f61711 100644 --- a/emulators/vice_x128.yml +++ b/emulators/vice_x128.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/vice-emu/" profiled_date: "2026-03-25" source_commit: "6cbc44add8b0a03791b343712dc63dc1edad2675" core_version: "3.10" +version_basis: + kind: file + path: "vice/configure" + pattern: '^VICE_VERSION=(\S+)' display_name: "Commodore - C128 (VICE x128)" cores: [vice_x128, x128] systems: [commodore-c128] diff --git a/emulators/vice_x64.yml b/emulators/vice_x64.yml index 0cb97f2a3..efec76790 100644 --- a/emulators/vice_x64.yml +++ b/emulators/vice_x64.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/vice-emu/" profiled_date: "2026-03-25" source_commit: "6cbc44add8b0a03791b343712dc63dc1edad2675" core_version: "3.10" +version_basis: + kind: file + path: "vice/configure" + pattern: '^VICE_VERSION=(\S+)' display_name: "Commodore - C64 (VICE x64, fast)" cores: [vice_x64, x64] systems: [commodore-c64] diff --git a/emulators/vice_x64dtv.yml b/emulators/vice_x64dtv.yml index b7289af66..f26a72ba8 100644 --- a/emulators/vice_x64dtv.yml +++ b/emulators/vice_x64dtv.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/vice-emu/" profiled_date: "2026-03-25" source_commit: "6cbc44add8b0a03791b343712dc63dc1edad2675" core_version: "3.10" +version_basis: + kind: file + path: "vice/configure" + pattern: '^VICE_VERSION=(\S+)' display_name: "Commodore - C64DTV (VICE x64dtv)" cores: [vice_x64dtv, x64dtv] systems: [commodore-c64dtv] diff --git a/emulators/vice_x64sc.yml b/emulators/vice_x64sc.yml index 673a159b5..705f53536 100644 --- a/emulators/vice_x64sc.yml +++ b/emulators/vice_x64sc.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/vice-emu/" profiled_date: "2026-03-25" source_commit: "6cbc44add8b0a03791b343712dc63dc1edad2675" core_version: "3.10" +version_basis: + kind: file + path: "vice/configure" + pattern: '^VICE_VERSION=(\S+)' display_name: "Commodore - C64 (VICE x64sc, accurate)" cores: [vice_x64sc, "x64sx"] systems: [commodore-c64] diff --git a/emulators/vice_xcbm2.yml b/emulators/vice_xcbm2.yml index 2fcd218d6..d88685e16 100644 --- a/emulators/vice_xcbm2.yml +++ b/emulators/vice_xcbm2.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/vice-emu/" profiled_date: "2026-03-25" source_commit: "6cbc44add8b0a03791b343712dc63dc1edad2675" core_version: "3.10" +version_basis: + kind: file + path: "vice/configure" + pattern: '^VICE_VERSION=(\S+)' display_name: "Commodore - CBM-II 6x0/7x0 (VICE xcbm2)" cores: [vice_xcbm2, xcbm2] systems: [commodore-cbm-ii] diff --git a/emulators/vice_xcbm5x0.yml b/emulators/vice_xcbm5x0.yml index cbbebb045..c4e4fbf61 100644 --- a/emulators/vice_xcbm5x0.yml +++ b/emulators/vice_xcbm5x0.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/vice-emu/" profiled_date: "2026-03-25" source_commit: "6cbc44add8b0a03791b343712dc63dc1edad2675" core_version: "3.10" +version_basis: + kind: file + path: "vice/configure" + pattern: '^VICE_VERSION=(\S+)' display_name: "Commodore - CBM-II 5x0 (VICE xcbm5x0)" cores: [vice_xcbm5x0, xcbm5x0] systems: [commodore-cbm-ii] diff --git a/emulators/vice_xpet.yml b/emulators/vice_xpet.yml index 34de820f7..71c0c4d81 100644 --- a/emulators/vice_xpet.yml +++ b/emulators/vice_xpet.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/vice-emu/" profiled_date: "2026-03-25" source_commit: "6cbc44add8b0a03791b343712dc63dc1edad2675" core_version: "3.10" +version_basis: + kind: file + path: "vice/configure" + pattern: '^VICE_VERSION=(\S+)' display_name: "Commodore - PET (VICE xpet)" cores: [vice_xpet, xpet] systems: [commodore-pet] diff --git a/emulators/vice_xplus4.yml b/emulators/vice_xplus4.yml index bbe39f124..8c66c1967 100644 --- a/emulators/vice_xplus4.yml +++ b/emulators/vice_xplus4.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/vice-emu/" profiled_date: "2026-03-25" source_commit: "6cbc44add8b0a03791b343712dc63dc1edad2675" core_version: "3.10" +version_basis: + kind: file + path: "vice/configure" + pattern: '^VICE_VERSION=(\S+)' display_name: "Commodore - PLUS/4 (VICE xplus4)" cores: [vice_xplus4, xplus4] systems: [commodore-plus4] diff --git a/emulators/vice_xscpu64.yml b/emulators/vice_xscpu64.yml index d82077c93..b260ed2eb 100644 --- a/emulators/vice_xscpu64.yml +++ b/emulators/vice_xscpu64.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/vice-emu/" profiled_date: "2026-03-25" source_commit: "6cbc44add8b0a03791b343712dc63dc1edad2675" core_version: "3.10" +version_basis: + kind: file + path: "vice/configure" + pattern: '^VICE_VERSION=(\S+)' display_name: "Commodore - C64 SuperCPU (VICE xscpu64)" cores: [vice_xscpu64, xscpu64] systems: [commodore-c64-supercpu] diff --git a/emulators/vice_xvic.yml b/emulators/vice_xvic.yml index 5f50b81a4..c1c80c99b 100644 --- a/emulators/vice_xvic.yml +++ b/emulators/vice_xvic.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/vice-emu/" profiled_date: "2026-03-25" source_commit: "6cbc44add8b0a03791b343712dc63dc1edad2675" core_version: "3.10" +version_basis: + kind: file + path: "vice/configure" + pattern: '^VICE_VERSION=(\S+)' display_name: "Commodore - VIC-20 (VICE xvic)" cores: [vice_xvic, xvic] systems: [commodore-vic20] diff --git a/emulators/video_processor.yml b/emulators/video_processor.yml index dd246ddcf..9a3e1f187 100644 --- a/emulators/video_processor.yml +++ b/emulators/video_processor.yml @@ -9,6 +9,10 @@ profiled_date: "2026-09-17" source_commit: "8fe4751f0039a1b645bf750531fcfc234958a7ac" upstream_commit: "c608ced893583e0a8a8153890f99453fd1647d53" core_version: "0.0.2" +version_basis: + kind: file + path: "video_processor_v4l2.c" + pattern: '#define LIBRARY_VERSION\s+"([^"]+)"' display_name: "Video Processor (V4L2)" cores: - video_processor diff --git a/emulators/vidtest.yml b/emulators/vidtest.yml index 81193887e..d690e1e5d 100644 --- a/emulators/vidtest.yml +++ b/emulators/vidtest.yml @@ -3,7 +3,12 @@ type: test core_classification: pure_libretro source: "https://github.com/schellingb/vidtest_libretro" profiled_date: "2026-03-25" +source_commit: "edfd32747e5eeb5ce82a5cee686ee1b32f1cc52e" core_version: "0.1" +version_basis: + kind: file + path: "vidtest.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "VidTest" cores: - vidtest diff --git a/emulators/vircon32.yml b/emulators/vircon32.yml index 8bd710232..4762ea9ed 100644 --- a/emulators/vircon32.yml +++ b/emulators/vircon32.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/vircon32/ComputerSoftware" profiled_date: "2026-03-25" source_commit: "8b4ff35efb0f3a4c2599fa85ec0e588713f83182" upstream_commit: "e75b5370ff2eaff986057b34df893ad2eba08ea5" -core_version: "2026.2.18" +core_version: "v1.7" +version_basis: + kind: tag + tag: "v1.7" + distance: 0 display_name: "Vircon32" cores: - vircon32 diff --git a/emulators/virtual-virtual-boy.yml b/emulators/virtual-virtual-boy.yml index d12b68939..7950d0cf9 100644 --- a/emulators/virtual-virtual-boy.yml +++ b/emulators/virtual-virtual-boy.yml @@ -7,7 +7,11 @@ author: "Simon Gellis" profiled_date: "2026-08-12" source_commit: "0bf230bced628d78ff2c149baaf16f6fb8388cec" upstream_commit: "0bf230bced628d78ff2c149baaf16f6fb8388cec" -core_version: "1.18.2" +core_version: "v1.18.2" +version_basis: + kind: tag + tag: "v1.18.2" + distance: 0 display_name: "Nintendo - Virtual Boy (Virtual Virtual Boy)" mode: standalone cores: diff --git a/emulators/virtualjaguar.yml b/emulators/virtualjaguar.yml index 882118a0f..22d614b73 100644 --- a/emulators/virtualjaguar.yml +++ b/emulators/virtualjaguar.yml @@ -6,6 +6,10 @@ upstream: "http://shamusworld.gotdns.org/git/virtualjaguar" profiled_date: "2026-09-04" source_commit: "e7db53678b86e2fceb459e26cf09d2fdaaa4d395" core_version: "v3.10.0" +version_basis: + kind: tag + tag: "v3.10.0" + distance: 0 display_name: "Atari - Jaguar (Virtual Jaguar)" cores: - virtualjaguar diff --git a/emulators/virtualxt.yml b/emulators/virtualxt.yml index 0f511bb1c..bd693d7be 100644 --- a/emulators/virtualxt.yml +++ b/emulators/virtualxt.yml @@ -6,6 +6,10 @@ upstream: "https://codeberg.org/virtualxt/virtualxt" profiled_date: "2026-10-17" source_commit: "a400adb0abf242c2fecbe926618338a00dc557c5" core_version: "3.1.0" +version_basis: + kind: file + path: "virtualxt_libretro.info" + pattern: '^display_version\s*=\s*"([^"]+)"' display_name: "VirtualXT" cores: [virtualxt] systems: [ibm-pc] diff --git a/emulators/visual-pinball.yml b/emulators/visual-pinball.yml index 52db2da2b..fe72f75f7 100644 --- a/emulators/visual-pinball.yml +++ b/emulators/visual-pinball.yml @@ -7,6 +7,11 @@ profiled_date: "2026-10-27" source_commit: "63770cd66eee66c84c10ba2f4d2edff918ab85d3" prose_written_at: "63770cd66eee66c84c10ba2f4d2edff918ab85d3" core_version: "10.8.1" +version_basis: + kind: file + path: "src/core/vpversion.h" + pattern: '#define VP_VERSION_MAJOR\s+(\d+)[^\n]*\n#define VP_VERSION_MINOR\s+(\d+)[^\n]*\n#define VP_VERSION_REV\s+(\d+)' + format: "{1}.{2}.{3}" display_name: "Visual Pinball X" cores: - vpinball diff --git a/emulators/vita3k.yml b/emulators/vita3k.yml index 19be65244..19be9d94f 100644 --- a/emulators/vita3k.yml +++ b/emulators/vita3k.yml @@ -4,7 +4,12 @@ source: "https://github.com/Vita3K/Vita3K" upstream: "https://github.com/Vita3K/Vita3K" profiled_date: "2026-10-23" source_commit: "6ec8e6ce31f3d6099b14eb9dd0320c09ef6386b6" -core_version: "0.2.1" +core_version: "v0.2.1" +version_basis: + kind: file + path: "vita3k/CMakeLists.txt" + pattern: 'set\(VITA3K_APP_VER_HI (\d+)\)\nset\(VITA3K_APP_VER_MID (\d+)\)\nset\(VITA3K_APP_VER_LO (\d+)\)\nset\(VITA3K_APP_VERSION "v' + format: "v{1}.{2}.{3}" display_name: "Vita3K (PS Vita)" cores: - vita3k diff --git a/emulators/vitaquake2.yml b/emulators/vitaquake2.yml index 94d07f1e0..074a20c78 100644 --- a/emulators/vitaquake2.yml +++ b/emulators/vitaquake2.yml @@ -6,7 +6,11 @@ upstream: "https://github.com/Rinnegatamante/vitaQuakeII" profiled_date: "2026-03-25" source_commit: "4b333fe18e8816974f04432af01f87654ae16e21" prose_written_at: "4b333fe18e8816974f04432af01f87654ae16e21" -core_version: "git" +core_version: "2.3" +version_basis: + kind: file + path: "qcommon/qcommon.h" + pattern: '^#define\s+VERSION\s+([0-9.]+)' display_name: "Quake II (vitaQuake 2)" cores: [vitaquake2, vitaquake2-rogue, vitaquake2-xatrix, vitaquake2-zaero] systems: [quake2] diff --git a/emulators/vitaquake3.yml b/emulators/vitaquake3.yml index 7d75d7287..2077870da 100644 --- a/emulators/vitaquake3.yml +++ b/emulators/vitaquake3.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/vitaquake3" upstream: "https://github.com/ioquake/ioq3" profiled_date: "2026-03-25" source_commit: "61374f650f42c4f25c215ea1f8db992af162ada6" -core_version: "git" +core_version: "1.36_GIT_ba68b99c-2018-01-23" +version_basis: + kind: file + path: "Makefile" + pattern: '-DPRODUCT_VERSION=\\"([^\\"]+)\\"' display_name: "Quake III: Arena (vitaQuake 3)" cores: [vitaquake3] systems: [quake3] diff --git a/emulators/vitavoyager.yml b/emulators/vitavoyager.yml index 28988e2f6..70a24dd62 100644 --- a/emulators/vitavoyager.yml +++ b/emulators/vitavoyager.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/vitavoyager" upstream: "https://github.com/clover-moe/lilium-voyager" profiled_date: "2026-03-25" source_commit: "58b70dd7ea891c2e8ddc37d03a5d58116b0ea118" -core_version: "git" +core_version: "1.36_GIT_ba68b99c-2018-01-23" +version_basis: + kind: file + path: "Makefile" + pattern: '-DPRODUCT_VERSION=\\"([^\\"]+)\\"' display_name: "Star Trek: Voyager - Elite Force (vitaVoyager)" cores: [vitavoyager] systems: [quake3] diff --git a/emulators/vkquake.yml b/emulators/vkquake.yml index 24fbee84a..fd0fd1c16 100644 --- a/emulators/vkquake.yml +++ b/emulators/vkquake.yml @@ -6,6 +6,11 @@ upstream: "https://sourceforge.net/projects/quakespasm/" profiled_date: "2026-10-23" source_commit: "a6cfba6904e0743dae4235f9dad9711bb5bd27f1" core_version: "1.37.1" +version_basis: + kind: file + path: "Quake/quakever.h" + pattern: '#define VKQUAKE_VERSION_MAJOR (\d+)\n#define VKQUAKE_VERSION_MINOR (\d+)\n#define VKQUAKE_VER_PATCH\s+(\d+)' + format: "{1}.{2}.{3}" display_name: "Quake (vkQuake)" cores: ["vkquake"] systems: [quake] diff --git a/emulators/vkquake2.yml b/emulators/vkquake2.yml index 946317b99..649fb92d6 100644 --- a/emulators/vkquake2.yml +++ b/emulators/vkquake2.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/id-Software/Quake-2" profiled_date: "2026-10-23" source_commit: "6763f207229f97cffabb6fc2da72017a794b139b" core_version: "1.5.10" +version_basis: + kind: tag + tag: "1.5.10" + distance: 0 display_name: "Quake II (vkQuake2)" cores: ["vkquake2"] systems: [quake2, xatrix, rogue, ctf] diff --git a/emulators/vkquake3.yml b/emulators/vkquake3.yml index 2b94f663e..45c527656 100644 --- a/emulators/vkquake3.yml +++ b/emulators/vkquake3.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/ioquake/ioq3" profiled_date: "2026-10-17" source_commit: "650bd625eb725446279c6176804b554e2e1c98f3" core_version: "1.36" +version_basis: + kind: file + path: "Makefile" + pattern: 'VERSION=([0-9][\w.+-]*)' display_name: "Quake III Arena (vkQuake3)" cores: ["vkquake3"] systems: [quake3, teamarena] diff --git a/emulators/vvvvvv.yml b/emulators/vvvvvv.yml index 4ed530e3a..05590f071 100644 --- a/emulators/vvvvvv.yml +++ b/emulators/vvvvvv.yml @@ -6,6 +6,11 @@ upstream: "https://github.com/TerryCavanagh/VVVVVV" profiled_date: "2026-10-23" source_commit: "40e1ec3bbf2a990a5c600564fe312c2121178a50" core_version: "v2.5" +version_basis: + kind: file + path: "desktop_version/src/ReleaseVersion.h" + pattern: '#define MAJOR_VERSION (\d+)\n#define MINOR_VERSION (\d+)\n#define PATCH_VERSION 0\b' + format: "v{1}.{2}" display_name: "VVVVVV" cores: - "vvvvvv" diff --git a/emulators/wasm4.yml b/emulators/wasm4.yml index ad49969d5..621246c88 100644 --- a/emulators/wasm4.yml +++ b/emulators/wasm4.yml @@ -5,7 +5,11 @@ source: "https://github.com/aduros/wasm4" upstream: "https://github.com/aduros/wasm4" profiled_date: "2026-03-25" source_commit: "9d6c962785cfe3719d0245fd279ecbe98a4dbb63" -core_version: "v2.7.1" +core_version: "2.7.1" +version_basis: + kind: file + path: "cli/package.json" + pattern: '"version":\s+"([^"]+)' display_name: "WASM-4" cores: [wasm4] systems: [] diff --git a/emulators/winuae.yml b/emulators/winuae.yml index 45daeac6a..602266b95 100644 --- a/emulators/winuae.yml +++ b/emulators/winuae.yml @@ -5,6 +5,11 @@ source: "https://github.com/tonioni/WinUAE" source_commit: "15110cf6606d1188800ea7ad86bf1cbd9c688741" profiled_date: "2026-10-20" core_version: "6.1.0 beta 19" +version_basis: + kind: file + path: "include/winuae_version.h" + pattern: '#define UAEMAJOR (\d+)\n#define UAEMINOR (\d+)\n#define UAESUBREV (\d+)\n\n#define WINUAEPUBLICBETA 1\n\n#if WINUAEPUBLICBETA\n#define WINUAEBETA _T\("(\d+)"\)' + format: "{1}.{2}.{3} beta {4}" display_name: "Commodore - Amiga (WinUAE)" cores: - winuae diff --git a/emulators/wolf4sdl.yml b/emulators/wolf4sdl.yml index c55166e56..6737502d1 100644 --- a/emulators/wolf4sdl.yml +++ b/emulators/wolf4sdl.yml @@ -5,7 +5,11 @@ source: "https://github.com/KS-Presto/Wolf4SDL" upstream: "https://github.com/KS-Presto/Wolf4SDL" profiled_date: "2026-10-20" source_commit: "dc8b250af35fb0ace68db5eb879490b50068c20e" -core_version: "2.0" +core_version: "v2.0" +version_basis: + kind: file + path: "wl_main.c" + pattern: '"Wolf4SDL (v[0-9][0-9.]*[0-9A-Za-z]*)\\n"' display_name: "Wolfenstein 3D (Wolf4SDL)" cores: [wolf4sdl] systems: [wolfenstein3d] diff --git a/emulators/wqxemu.yml b/emulators/wqxemu.yml index 226e7b9a5..36ec2a35c 100644 --- a/emulators/wqxemu.yml +++ b/emulators/wqxemu.yml @@ -7,6 +7,10 @@ profiled_date: "2026-10-18" source_commit: "caf0998989446e3d6659f67c1b8aabd708a0379d" upstream_commit: "caf0998989446e3d6659f67c1b8aabd708a0379d" core_version: "0.1.0" +version_basis: + kind: file + path: "Cargo.toml" + pattern: 'version\s+=\s+"([^"]+)' display_name: "Wenquxing - Electronic Dictionary (WQXEmu)" cores: - wqxemu diff --git a/emulators/x1-box.yml b/emulators/x1-box.yml index 0bf800383..17220ac2c 100644 --- a/emulators/x1-box.yml +++ b/emulators/x1-box.yml @@ -8,6 +8,10 @@ profiled_date: "2026-10-26" source_commit: "e092175b9196438ee2712bf6f45398fe2970b5fe" upstream_commit: "26fcbe54f17e496bdf530dad9f237e74e2f943fc" core_version: "1.3.2" +version_basis: + kind: tag + tag: "1.3.2" + distance: 0 display_name: "Microsoft - Xbox (X1 BOX)" cores: - "x1-box" diff --git a/emulators/x1.yml b/emulators/x1.yml index 30e3cd072..380524d9e 100644 --- a/emulators/x1.yml +++ b/emulators/x1.yml @@ -6,6 +6,10 @@ upstream: "http://amethyst.yui.ne.jp/svn/x1/xmil/trunk/" profiled_date: "2026-03-25" source_commit: "3106aa54ffb244cca4019a6e95dacaa698781bc3" core_version: "0.60a" +version_basis: + kind: file + path: "xmilver.h" + pattern: '#define\s+XMILVER_CORE\s+"ver\.([^"]+)"' display_name: "Sharp X1 (X Millennium)" cores: - x1 diff --git a/emulators/x16emu.yml b/emulators/x16emu.yml index 3d2d52400..d4b011799 100644 --- a/emulators/x16emu.yml +++ b/emulators/x16emu.yml @@ -5,6 +5,10 @@ upstream: "https://github.com/X16Community/x16-emulator" profiled_date: "2026-10-20" source_commit: "af1024080ced455ea098b007aed43142c99e93da" core_version: "r49" +version_basis: + kind: tag + tag: "r49" + distance: 0 display_name: "Commander X16 (x16emu)" cores: - x16emu diff --git a/emulators/x64sdl.yml b/emulators/x64sdl.yml index cb74df3b6..d9222de86 100644 --- a/emulators/x64sdl.yml +++ b/emulators/x64sdl.yml @@ -6,6 +6,10 @@ upstream: "https://sourceforge.net/projects/vice-emu/" profiled_date: "2026-03-25" source_commit: "baaaeed97ce1c0a07ed78e3e155cfbd6f508b472" core_version: "3.1" +version_basis: + kind: file + path: "src/version.h" + pattern: '#define\s+VERSION\s+"([^"]+)' display_name: "Commodore - C64 (VICE SDL)" cores: [x64sdl] systems: [commodore-c64] diff --git a/emulators/xash3d_fwgs.yml b/emulators/xash3d_fwgs.yml index f4e99b9a1..aecc372d1 100644 --- a/emulators/xash3d_fwgs.yml +++ b/emulators/xash3d_fwgs.yml @@ -5,7 +5,11 @@ source: "https://github.com/FWGS/xash3d-fwgs" upstream: "https://github.com/FWGS/xash3d-fwgs" profiled_date: "2026-10-04" source_commit: "27092af50d912432887faa43a1cccddfae569b2d" -core_version: "0.21+git" +core_version: "0.21" +version_basis: + kind: file + path: "engine/common/com_strings.h" + pattern: '#define\s+XASH_VERSION\s+"([^"]+)"' display_name: "Xash3D FWGS" cores: [xash3d_fwgs, xash3d] systems: [halflife, cstrike, czero, czeror, dmc, gearbox, bshift, ricochet, tfc] diff --git a/emulators/xemu-chihiro.yml b/emulators/xemu-chihiro.yml index ab82e0e92..a7709ddd6 100644 --- a/emulators/xemu-chihiro.yml +++ b/emulators/xemu-chihiro.yml @@ -7,7 +7,12 @@ upstream: "https://github.com/xemu-project/xemu" profiled_date: "2026-10-20" source_commit: "98fbd75dd0f3088a4988abc1698feb37b844a41a" upstream_commit: "25e1ee2fd59a451f2ab57e825b4f8a5414220c8b" -core_version: "0.8.134-406-g0d44d803b2" +core_version: "v0.8.134-410-g98fbd75" +version_basis: + kind: tag + match: "v*" + tag: "v0.8.134" + distance: 410 display_name: "Sega - Chihiro (xemu Chihiro)" cores: - xemu-chihiro diff --git a/emulators/xemu.yml b/emulators/xemu.yml index 3c9f47dec..f242bd2f3 100644 --- a/emulators/xemu.yml +++ b/emulators/xemu.yml @@ -11,8 +11,18 @@ source_commit: standalone: "25e1ee2fd59a451f2ab57e825b4f8a5414220c8b" libretro: "d9804db79f87f6a6a5548b14ca4a8d5164390338" core_version: - standalone: "0.8.139-2-g25e1ee2fd5" + standalone: "v0.8.139-2-g25e1ee2" libretro: "libretro-experimental" +version_basis: + standalone: + kind: tag + match: "v*" + tag: "v0.8.139" + distance: 2 + libretro: + kind: file + path: "ui/xemu-libretro.c" + pattern: 'info->library_version\s*=\s*"([^"]+)"' display_name: "Microsoft - Xbox (xemu)" cores: - xemu diff --git a/emulators/xendroid.yml b/emulators/xendroid.yml index f712a9d2e..f48b11da5 100644 --- a/emulators/xendroid.yml +++ b/emulators/xendroid.yml @@ -7,7 +7,11 @@ author: "rfandango" profiled_date: "2026-09-17" source_commit: "779680ade075d2d2a4c589c6a8d57a8e26c116c0" upstream_commit: "d881a29125978b4eea6bf44f6ed8c33f8aea8c33" -core_version: "0b11201" +core_version: "XenDroid-0b11201-2-g779680a" +version_basis: + kind: tag + tag: "XenDroid-0b11201" + distance: 2 display_name: "Microsoft - Xbox 360 (XenDroid)" cores: - "xendroid" diff --git a/emulators/xenia-edge.yml b/emulators/xenia-edge.yml index 3fa27d61c..d4d8bd446 100644 --- a/emulators/xenia-edge.yml +++ b/emulators/xenia-edge.yml @@ -12,6 +12,15 @@ profiled_date: "2026-10-27" core_version: standalone: "7180422" libretro: "8dc77b0" +version_basis: + standalone: + kind: tag + tag: "7180422" + distance: 0 + libretro: + kind: file + path: "upstream.version" + pattern: '\A([0-9a-f]{7,40})\s*$' display_name: "Xenia Edge (Xbox 360)" cores: - "xenia-edge" diff --git a/emulators/xenia.yml b/emulators/xenia.yml index 57c49bba9..b0ff32c4f 100644 --- a/emulators/xenia.yml +++ b/emulators/xenia.yml @@ -5,7 +5,11 @@ source: "https://github.com/xenia-canary/xenia-canary" upstream: "https://github.com/xenia-canary/xenia-canary" profiled_date: "2026-03-26" source_commit: "72c2afa3ba2b1b232f89de71577251d6edafb1bd" -core_version: "canary" +core_version: "72c2afa" +version_basis: + kind: tag + tag: "72c2afa" + distance: 0 display_name: "Xenia Canary (Xbox 360)" cores: - xenia diff --git a/emulators/xenios.yml b/emulators/xenios.yml index e1f648ef6..cc9440da6 100644 --- a/emulators/xenios.yml +++ b/emulators/xenios.yml @@ -6,7 +6,12 @@ upstream: "https://github.com/has207/xenia-edge" source_commit: "87b176a078c316fde3adf67a217f0c44615b0e0d" upstream_commit: "07021f019cf55105bc26c0474e0b0835808353e2" profiled_date: "2026-08-23" -core_version: "2.0.1" +core_version: "v2.0.1-2-g87b176a" +version_basis: + kind: tag + match: "v[0-9]*.[0-9]*.[0-9]*" + tag: "v2.0.1" + distance: 2 display_name: "Microsoft - Xbox 360 (XeniOS)" cores: - "xenios" diff --git a/emulators/xm6pro68k.yml b/emulators/xm6pro68k.yml index 44f605745..4d847f341 100644 --- a/emulators/xm6pro68k.yml +++ b/emulators/xm6pro68k.yml @@ -9,6 +9,10 @@ version_source: based_on: "XM6 v2.06 by PI." profiled_date: "2026-10-20" core_version: "260920" +version_basis: + kind: package + url: "https://www.retrobat.ovh/repo/win64/stable/emulators/xm6pro.7z" + artifact: "xm6pro.7z, Version.txt" display_name: "XM6 Pro-68k (Sharp X68000)" mode: standalone cores: diff --git a/emulators/xm6typeg.yml b/emulators/xm6typeg.yml index c44b057ec..666cf9834 100644 --- a/emulators/xm6typeg.yml +++ b/emulators/xm6typeg.yml @@ -9,6 +9,12 @@ version_source: based_on: "XM6 v2.06 by PI." profiled_date: "2026-08-10" core_version: "3.38" +version_basis: + kind: package + url: "http://retropc.net/pi/xm6/index.html" + pattern: 'xm6_typeg_(\d)(\d+)_\d+\.zip' + format: "{1}.{2}" + artifact: "xm6_typeg_338_20260223.zip" display_name: "XM6 TypeG (Sharp X68000)" mode: standalone cores: diff --git a/emulators/xm7.yml b/emulators/xm7.yml index 6a771ae01..e44af9a08 100644 --- a/emulators/xm7.yml +++ b/emulators/xm7.yml @@ -7,6 +7,11 @@ upstream: "http://retropc.net/ryu/xm7/" profiled_date: "2026-10-20" source_commit: "2a48dceaf8a3a0de92cf369b039ac5fab2bb351a" core_version: "V3.4 L61a SDL/Agar 0.3.2pre2" +version_basis: + kind: file + path: "linux-sdl/vm/xm7.h" + pattern: '#if XM7_VER >= 3\n#define\s+VERSION\s+"(V[^"]+)"[\s\S]*?#else\n#define\s+LEVEL\s+"([^"]+)"[\s\S]*?#else\n#define\s+LOCALVER\s+"(SDL/Agar [^"]+)"' + format: "{1} {2} {3}" cores: - xm7 systems: diff --git a/emulators/xrick.yml b/emulators/xrick.yml index 08b56de5a..62ac214d7 100644 --- a/emulators/xrick.yml +++ b/emulators/xrick.yml @@ -5,7 +5,11 @@ source: "https://github.com/libretro/xrick-libretro" upstream: "https://github.com/fabiensanglard/xrick" profiled_date: "2026-03-30" source_commit: "fcfde3623a04b4e986548e06d46630fcd0bd1e18" -core_version: "1.0.0.6" +core_version: "021212" +version_basis: + kind: file + path: "include/config.h" + pattern: '#define\s+VERSION\s+"([^"]+)"' display_name: "Rick Dangerous (XRick)" cores: - xrick diff --git a/emulators/xroar.yml b/emulators/xroar.yml index 38d7ff49e..4729f716a 100644 --- a/emulators/xroar.yml +++ b/emulators/xroar.yml @@ -7,6 +7,9 @@ version_source: pattern: 'version\s*<strong>([0-9.]+)</strong>, released' profiled_date: "2026-10-20" core_version: "1.12.1" +version_basis: + kind: unverified + why: host_unsupported display_name: "Dragon / CoCo / MC-10 (XRoar)" cores: - xroar diff --git a/emulators/yabasanshiro.yml b/emulators/yabasanshiro.yml index 641f2bdd7..859ed3400 100644 --- a/emulators/yabasanshiro.yml +++ b/emulators/yabasanshiro.yml @@ -10,8 +10,18 @@ source_commit: libretro: "09ed8e5b2e97e7a848ea2514545c34c7b809e399" standalone: "a40dace1ae0af3ebd45848549fdf396f40e3930f" core_version: - libretro: "v2.6.8" + libretro: "3.4.2" standalone: "1.11.beta3" +version_basis: + libretro: + kind: file + path: "yabause/src/libretro/Makefile.common" + pattern: '-DVERSION=\\"([^\\"]+)\\"' + standalone: + kind: file + path: "yabause/CMakeLists.txt" + pattern: 'set\(YAB_VERSION_MAJOR (\w+)\)\nset\(YAB_VERSION_MINOR (\w+)\)\nset\(YAB_VERSION_PATCH (\w+)\)' + format: "{1}.{2}.{3}" display_name: "Sega - Saturn (YabaSanshiro)" cores: - yabasanshiro diff --git a/emulators/yabause.yml b/emulators/yabause.yml index 1d05ae06c..1a83c8fc0 100644 --- a/emulators/yabause.yml +++ b/emulators/yabause.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/Yabause/yabause" profiled_date: "2026-03-25" source_commit: "8926b0c6c347f8c5c755911ddb0ac695420ffbf8" core_version: "v0.9.15" +version_basis: + kind: file + path: "yabause/src/libretro/libretro.c" + pattern: 'info->library_version\s+=\s+"([^"]+)' display_name: "Sega - Saturn (Yabause)" cores: - yabause diff --git a/emulators/yaps2.yml b/emulators/yaps2.yml index 25111d394..07ed63931 100644 --- a/emulators/yaps2.yml +++ b/emulators/yaps2.yml @@ -8,7 +8,13 @@ profiled_date: "2026-09-17" source_commit: "57ea93c0ce8306063b31fe6658dab6b492bbedfe" upstream_commit: "342db51523f288c5ced20f5be3c679f46472cc45" upstream_frozen: "The tree is PCSX2 at this commit plus the fork's own commits. Later PCSX2 commits are not in the port." -core_version: "Git" +core_version: "v2.7.421" +version_basis: + kind: tag + repo: upstream + match: "v*" + tag: "v2.7.421" + distance: 0 display_name: "Sony - PlayStation 2 (yaps2)" cores: [yaps2] systems: [sony-playstation-2] diff --git a/emulators/ymir.yml b/emulators/ymir.yml index 284850d0e..45d1b395b 100644 --- a/emulators/ymir.yml +++ b/emulators/ymir.yml @@ -10,8 +10,17 @@ source_commit: standalone: "fe439e98abc555c243a8a197850c71777ff664f4" libretro: "8174cbbeea4070654841cdd4604361b3eee8fdd1" core_version: - standalone: "v0.4.1-84-gfe439e98" - libretro: "libretro branch" + standalone: "0.4.2" + libretro: "0.4.0" +version_basis: + standalone: + kind: file + path: "CMakeLists.txt" + pattern: '^project\(Ymir VERSION ([0-9][^ )]*)\)' + libretro: + kind: file + path: "CMakeLists.txt" + pattern: '^project\(Ymir VERSION ([0-9][^ )]*)\)' display_name: "Sega - Saturn (Ymir)" cores: - ymir diff --git a/emulators/yquake2.yml b/emulators/yquake2.yml index 19cf021a9..bdb74943d 100644 --- a/emulators/yquake2.yml +++ b/emulators/yquake2.yml @@ -5,7 +5,11 @@ source: "https://github.com/yquake2/yquake2" upstream: "https://github.com/yquake2/yquake2" profiled_date: "2026-10-04" source_commit: "9dbf699273e2546f3ad14cff3dee6a51a518cd2a" -core_version: "8.51+git" +core_version: "8.71pre" +version_basis: + kind: file + path: "src/common/header/common.h" + pattern: '#define\s+YQ2VERSION\s+"([^"]+)"' display_name: "Yamagi Quake II" cores: [yquake2] systems: [quake2, xatrix, rogue, ctf] diff --git a/emulators/yuzu.yml b/emulators/yuzu.yml index 529a1cb26..e425668bf 100644 --- a/emulators/yuzu.yml +++ b/emulators/yuzu.yml @@ -9,6 +9,9 @@ pin_frozen: "The analysed revision, the one the EA 4176 build documented here co upstream_gone: "GitHub withdrew the repository for legal reasons: the API answers HTTP 451 for both yuzu-emu/yuzu and the yuzu-emu-mirror copy. Observed 2026-09-04. The fork Zenfone-5-X00QD-4-19/yuzu, pushed 2024-03-05, still serves the analysed commit." source_mirror: "https://github.com/Zenfone-5-X00QD-4-19/yuzu" core_version: "EA 4176" +version_basis: + kind: unverified + why: host_gone display_name: "Yuzu (Nintendo Switch)" cores: - yuzu diff --git a/emulators/zc210.yml b/emulators/zc210.yml index 90cfb3cf4..6a1f502ca 100644 --- a/emulators/zc210.yml +++ b/emulators/zc210.yml @@ -3,7 +3,12 @@ type: libretro core_classification: game_engine source: https://github.com/netux79/zc210-libretro upstream: https://www.zeldaclassic.com/ -core_version: "2.10 Beta 5" +core_version: "2.10" +version_basis: + kind: file + path: "zc/zdefs.h" + pattern: '#define\s+ZELDA_VERSION\s+0x0*([0-9])([0-9]{2})\b' + format: "{1}.{2}" display_name: Zelda Classic v2.10 (ZC210) profiled_date: "2026-03-26" source_commit: "b6426da40b074245fda097fd345fa7c9cdbf152a" diff --git a/emulators/zc255.yml b/emulators/zc255.yml index 7ac94e1a9..b9387c9ee 100644 --- a/emulators/zc255.yml +++ b/emulators/zc255.yml @@ -5,6 +5,10 @@ source: "https://www.retrobat.ovh/repo/win64/stable/emulators/cores/zc255_libret upstream: closed-source profiled_date: "2026-10-20" core_version: "2.55.16" +version_basis: + kind: package + url: "https://www.retrobat.ovh/repo/win64/stable/emulators/cores/zc255_libretro.dll.zip" + artifact: "zc255_libretro.dll.zip, RetroBat coreversions.xml entry" display_name: "Zelda Classic 2.55 (ZC255)" cores: [zc255] systems: [zeldaclassic] diff --git a/emulators/zesarux.yml b/emulators/zesarux.yml index 728e9d1c3..3017ab21f 100644 --- a/emulators/zesarux.yml +++ b/emulators/zesarux.yml @@ -7,6 +7,10 @@ source_commit: "fd354296d851edc24ad1411b8f9342a66d07d460" prose_written_at: "e1fc8db2957c360c8ff584a2c4d147f70861c3aa" profiled_date: "2026-10-26" core_version: "13.1-SN" +version_basis: + kind: file + path: "src/cpu.h" + pattern: '^#define\s+EMULATOR_VERSION\s+"([^"]+)"' display_name: "Sinclair - ZX Spectrum and clones (ZEsarUX)" verification: existence cores: [zesarux] diff --git a/emulators/zinc.yml b/emulators/zinc.yml index 2dbcc21b0..8c45a43af 100644 --- a/emulators/zinc.yml +++ b/emulators/zinc.yml @@ -6,6 +6,10 @@ upstream: closed-source author: "Drunken Muppets" profiled_date: "2026-10-20" core_version: "1.1" +version_basis: + kind: package + url: "https://www.retrobat.ovh/repo/win64/stable/emulators/zinc.7z" + artifact: "zinc.7z, ZiNc.exe banner" display_name: "Arcade - Sony ZN-1/ZN-2, Namco System 11, Konami GV (ZiNc)" cores: - zinc diff --git a/emulators/zquestclassic.yml b/emulators/zquestclassic.yml index 10da14d2d..b606049d6 100644 --- a/emulators/zquestclassic.yml +++ b/emulators/zquestclassic.yml @@ -6,6 +6,10 @@ upstream: "https://github.com/ZQuestClassic/ZQuestClassic" source_commit: "4ef771c64666812a1359b8f34fe4d7803868ba13" profiled_date: "2026-10-20" core_version: "2.55.17" +version_basis: + kind: tag + tag: "2.55.17" + distance: 0 display_name: "Zelda Classic (ZQuest Classic)" cores: [zquestclassic] systems: [zeldaclassic] diff --git a/install.ps1 b/install.ps1 index 4d00044ce..615575afc 100644 --- a/install.ps1 +++ b/install.ps1 @@ -11,7 +11,7 @@ $ErrorActionPreference = "Stop" $defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py" - $defaultInstallSha256 = "825b55c17403287319a0c7d6e118e34d1bbf21cf0e6e66029c6c7eb767d2e0cb" + $defaultInstallSha256 = "7757b36db5beb3cbeb3717e0736db630237e87da5189a14d5092e679b69156af" $maximumInstallerBytes = 2MB $installerExit = 0 $installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null } diff --git a/install.py b/install.py index 7cbc3f95c..d7b2a6bda 100644 --- a/install.py +++ b/install.py @@ -12809,7 +12809,15 @@ _PASTE_END = "\x1b[201~" # Turned on by the interface, so a pasted path arrives as one piece and its # newline does not submit it half typed. _SCREEN_ON = "\x1b[?1049h\x1b[?25l\x1b[?2004h\x1b[2J" -_SCREEN_OFF = "\x1b[?2004l\x1b[0m\x1b[?25h\x1b[?1049l" +# The mouse modes are turned off on every way out, turned on or not: a +# shell left with them on reads each click as a line of garbage. +_SCREEN_OFF = "\x1b[?1006l\x1b[?1000l\x1b[?2004l\x1b[0m\x1b[?25h\x1b[?1049l" +# Presses and releases (1000), reported in SGR form (1006): a column past +# 223 does not fit the legacy form's byte. Never 1003 (every motion): a +# touch screen has no hover, and nothing here depends on one. +_MOUSE_ON = "\x1b[?1000h\x1b[?1006h" +_MOUSE_OFF = "\x1b[?1006l\x1b[?1000l" +TUI_MOUSE_ENV = "RETROBIOS_NO_MOUSE" # How a line is drawn without colour: the screen's title and a headline # bold, the row in focus reversed, the bar and secondary text dim. _STYLES = {"title": "\x1b[1m", "head": "\x1b[1m", "focus": "\x1b[7m", "dim": "\x1b[2m", @@ -12830,6 +12838,40 @@ class TuiKey(NamedTuple): text: str = "" +class TuiMouse(NamedTuple): + """One mouse report: the button (0 left, 1 middle, 2 right, 3 a legacy + release, 64 and 65 the wheel, plus 4, 8 and 16 for Shift, Meta and + Ctrl), the cell counted from 1, and whether the button went up.""" + + button: int + col: int + row: int + release: bool = False + name: str = "mouse" + text: str = "" + + +def _sgr_mouse(params: str, final: str) -> TuiMouse | None: + """An SGR report: ESC [ < button ; column ; row, M pressed, m released.""" + parts = params[1:].split(";") + if len(parts) != 3 or not all(part.isdigit() for part in parts): + return None + button, col, row = (int(part) for part in parts) + return TuiMouse(button, col, row, final == "m") + + +def _x10_mouse(data: str) -> TuiMouse | None: + """A legacy report: three characters, each 32 plus its value. A + position past 95 is a byte UTF-8 cannot read, and the report is dropped.""" + codes = [ord(char) - 32 for char in data] + if any(not 0 <= code <= 223 for code in codes): + return None + button, col, row = codes + if col < 1 or row < 1: + return None + return TuiMouse(button, col, row, button & 3 == 3 and not button & 64) + + _CSI_KEYS = {"A": "up", "B": "down", "C": "right", "D": "left", "H": "home", "F": "end", "Z": "shift-tab"} _TILDE_KEYS = {"1": "home", "7": "home", "4": "end", "8": "end", "5": "pgup", "6": "pgdn", @@ -12853,7 +12895,9 @@ def _plain_key(char: str) -> TuiKey | None: return TuiKey("char", char) -def _csi_key(params: str, final: str) -> TuiKey | None: +def _csi_key(params: str, final: str) -> TuiKey | TuiMouse | None: + if params.startswith("<"): + return _sgr_mouse(params, final) if final in "Mm" else None if final == "~": if params == "200": return TuiKey("paste-start") @@ -12869,15 +12913,16 @@ def _csi_key(params: str, final: str) -> TuiKey | None: return None -def _escape(buffer: str) -> tuple[int, TuiKey | None]: +def _escape(buffer: str) -> tuple[int, TuiKey | TuiMouse | None]: """The sequence at the start of buffer: the characters it takes and its key (None for one nobody bound), or 0 while more are needed to tell.""" if len(buffer) < 2: return 0, None if buffer[1] == "[": if buffer[2:3] == "M": - # An X10 mouse report: three bytes of position follow. - return (6, None) if len(buffer) >= 6 else (0, None) + # A legacy mouse report: three bytes of button and position + # follow, read as a report and never as keys. + return (6, _x10_mouse(buffer[3:6])) if len(buffer) >= 6 else (0, None) for end in range(2, len(buffer)): code = ord(buffer[end]) if 0x40 <= code <= 0x7E: @@ -12896,7 +12941,8 @@ def _escape(buffer: str) -> tuple[int, TuiKey | None]: class KeyDecoder: """Keys from what a terminal sends, however the reads split it. - Unknown sequences (F13, mouse reports) are dropped, never taken as text. + Unknown sequences (F13) are dropped, never taken as text. A mouse + report, SGR or legacy, comes out as a TuiMouse. """ def __init__(self) -> None: @@ -13093,9 +13139,14 @@ def _wrap(text: str, width: int, indent: str = " ", whole: str = "") -> list[st class TuiLine(str): """A screen line and how it is drawn: "head" (the screen's title), - "title", "focus", "dim", "hint" (the bar), "refusal" or plain.""" + "title", "focus", "dim", "hint" (the bar), "refusal" or plain. + + mark is what a click on the line reaches (tui_hits): ("row", index, + (action, value)) for a row of the list, ("scroll", kind, rows) for the + line saying which lines are in view, ("bar",) for the bar.""" style = "" + mark: tuple | None = None def _styled(text: str, style: str = "") -> TuiLine: @@ -13229,6 +13280,12 @@ class TuiState: self.card_note: str = "" # The rows the last view drew in its list, what a page moves by. self.page_rows: int = 0 + # The targets of the frame on screen (tui_hits), the target a + # button went down on, and per screen the first row of a list the + # wheel scrolled. + self.hits: TuiHits | None = None + self.pressed: tuple | None = None + self.list_top: dict = {} # The mounted cards of that system, as last looked for. self.cards: list | None = None # (width and text, lines) of the last pager wrapped. @@ -13691,6 +13748,52 @@ def tui_blocker( return "" +# TERM values of terminals that report no mouse the xterm way: the Linux +# console (gpm is its own protocol), the DEC VTs and BSD consoles. +_NO_MOUSE_TERMS = ("linux", "vt", "cons", "ansi") + + +def tui_mouse_blocker( + stdin: TextIO | None = None, stdout: TextIO | None = None, + env: Mapping[str, str] | None = None, +) -> str: + """Why the full screen leaves the mouse to the terminal, "" when it + asks for clicks. A pad route has no pointer and its mapper may send + anything a report would be confused with, and RETROBIOS_NO_MOUSE keeps + the terminal's own selection everywhere.""" + env = os.environ if env is None else env + stdin = stdin or sys.stdin + stdout = stdout or sys.stdout + if _env_on(env, TUI_MOUSE_ENV): + return f"{TUI_MOUSE_ENV} is set" + if env.get(TUI_PAD_ENV, "").strip(): + return f"{TUI_PAD_ENV} names a controller route" + if os.name == "nt": + # msvcrt.getwch reads keys, never a console mouse record. + return "a Windows console reports no clicks as keys" + for name, stream in (("input", stdin), ("output", stdout)): + isatty = getattr(stream, "isatty", None) + if not (isatty and isatty()): + return f"the {name} is not a terminal" + term = env.get("TERM", "").strip().lower() + if term in ("", "dumb", "unknown") or term.startswith(_NO_MOUSE_TERMS): + return f"TERM={term} reports no clicks" if term else "TERM is not set" + return "" + + +def tui_wants_mouse(state: TuiState, lines: list[str]) -> bool: + """Whether the frame takes clicks: not where a command or the result is + shown, so the terminal's own selection copies it as it always has, nor + where a path is typed, which a middle or right click pastes into.""" + if state.help: + return True + if state.screen in ("result", "command", "path"): + return False + hint = tui_hint(state) + text = " ".join(" ".join(str(line).split()) for line in lines) + return not any(launcher in text for launcher in (hint.launcher(), hint.launcher(True))) + + def tui_flags(state: TuiState) -> list[tuple[str, str | None]]: """The options that carry the choices made on screen, CLI ones included.""" flags = list(state.passthrough) @@ -15661,6 +15764,8 @@ def _pager_last(state: TuiState, items: list) -> int: def tui_update(state: TuiState, key: TuiKey) -> list[tuple]: """What a key does on the current screen, and the work it starts.""" + if key.name == "mouse": + return tui_mouse(state, key) # type: ignore[arg-type] if key.name in ("ctrl-c", "ctrl-d"): return tui_interrupt(state) if state.cols < TUI_MIN_COLS or state.rows < TUI_MIN_ROWS: @@ -15791,6 +15896,103 @@ def tui_update(state: TuiState, key: TuiKey) -> list[tuple]: return [] +# Lines one notch of the wheel moves. +TUI_WHEEL_LINES = 3 + + +def tui_mouse(state: TuiState, event: TuiMouse) -> list[tuple]: + """What a click, a tap or the wheel does, read against the frame on + screen when it came (state.hits): a frame drawn for another screen, or + a row no longer where it was drawn, does nothing. + + A tap acts when the button goes up, on the target it went down on: a + swipe that ends elsewhere does nothing. On a row it focuses the row, + and on the row in focus it does what Enter does: one terminal row is + far smaller than a finger, and a single tap acting on it would act on + a near miss. On a bar entry it presses that entry's key. The right and + middle buttons do nothing, nor a click with Shift, Meta or Ctrl held, + which the terminal keeps for its own selection and links. + """ + hits = state.hits + if (event.button & 32 or hits is None or hits.screen != state.screen + or hits.help != state.help or hits.size != (state.cols, state.rows) + or state.cols < TUI_MIN_COLS or state.rows < TUI_MIN_ROWS or state.app_running): + state.pressed = None + return [] + target = hits.at(event.col - 1, event.row - 1) + if event.button & 64: + if event.release or event.button & 3 > 1 or state.help: + return [] + return _wheel(state, hits, 1 if event.button & 1 else -1) + if event.button & 28: + state.pressed = None + return [] + button = event.button & 3 + if not event.release: + state.pressed = (state.screen, state.help, target) if button == 0 else None + return [] + pressed, state.pressed = state.pressed, None + if button not in (0, 3) or pressed != (state.screen, state.help, target): + return [] + if state.help: + # Any key closes the help, a tap too. + state.help = False + return [] + if target is None: + return [] + if target[0] == "key": + return tui_update(state, target[1]) + if target[0] == "scroll": + return _scroll_tap(state, target[1]) + rows = tui_rows(state) + index = target[1] + if index >= len(rows) or (rows[index].action, rows[index].value) != target[2]: + return [] + screen = state.screen + if state.editing: + state.editing = "" + elif max(0, min(state.focus.get(screen, 0), len(rows) - 1)) == index: + return tui_update(state, TuiKey("enter")) + state.status = state.status_more = "" + state.focus[screen] = index + return [] + + +def _wheel(state: TuiState, hits: TuiHits, step: int) -> list[tuple]: + """A notch of the wheel: the list, the message or the text moves, and + the focus moves only when it would leave the rows in view.""" + screen = state.screen + lines = step * TUI_WHEEL_LINES + if hits.listing is not None: + first, shown, total = hits.listing + top = max(0, min(first + lines, total - shown)) + state.list_top[screen] = top + rows = tui_rows(state) + focus = max(0, min(state.focus.get(screen, 0), len(rows) - 1)) + state.focus[screen] = max(top, min(focus, top + shown - 1)) + elif hits.scroll == "error": + state.focus["error_text"] = max(0, state.focus.get("error_text", 0) + lines) + elif hits.scroll == "pager": + last = _pager_last(state, _pager_items(state)) + state.focus[screen] = max(0, min(state.focus.get(screen, 0) + lines, last)) + return [] + + +def _scroll_tap(state: TuiState, kind: str) -> list[tuple]: + """A tap on the line saying which lines are in view: the next page, + and from the last one the first.""" + before = (dict(state.focus), dict(state.list_top)) + effects = tui_update(state, TuiKey("pgdn")) + # The view keeps a scroll inside the text: measured, not guessed. + tui_view(state, state.cols, state.rows) + if (dict(state.focus), dict(state.list_top)) != before: + return effects + if kind == "error": + state.focus["error_text"] = 0 + return effects + return effects + tui_update(state, TuiKey("home")) + + # The routes inside muxterm, where no button sends PgUp or PgDn. _NO_PAGE_PADS = ("muxterm", "gptokeyb_muxterm") @@ -16118,6 +16320,12 @@ def _text_lines(items: list, width: int, whole: bool = False) -> list[TuiLine]: lines: list[TuiLine] = [] for item in items: style = getattr(item, "style", "") + if getattr(item, "mark", None) is not None: + # A line saying which lines are in view keeps what a click on it does. + line = _styled(fit(str(item), width), style) + line.mark = item.mark + lines.append(line) + continue if style == "path" and not whole: # One line, cut in its middle: the end of a path tells it apart. lines.append(_styled(middle(str(item), width))) @@ -16176,14 +16384,25 @@ def _compose( return top_lines + _compose(state, width, room, before, rows, after) + footer_lines focus = max(0, min(state.focus.get(state.screen, 0), len(rows) - 1)) if rows else 0 row_lines = [_row_line(row, index == focus, width) for index, row in enumerate(rows)] + for index, (row, line) in enumerate(zip(rows, row_lines)): + line.mark = ("row", index, (row.action, row.value)) # What L1/R1 move by: the rows drawn. Six fewer than the window's height # skipped rows the intro left no room for at 40x12, muOS among them. state.page_rows = max(1, min(len(row_lines), room - 1)) if len(row_lines) >= room: first = focus - (room - 1) // 2 + # Scrolled by the wheel, the list stays where it was put while the + # focus is in view: centred again, the row under the pointer moved. + top = state.list_top.get(state.screen) + if top is not None and top <= focus < top + max(1, room - 1): + first = top + else: + state.list_top.pop(state.screen, None) lead = next((i for i, row in enumerate(rows) if row.action not in ("all", "none", "filter")), 0) body = _scrolled(row_lines, first, room, lead) + if len(row_lines) > room: + body[-1].mark = ("scroll", "list", len(rows)) else: budget = room - len(row_lines) top: list[TuiLine] = [] @@ -16230,7 +16449,9 @@ def _pager( skip = starts[lead] if lead else 0 start = max(1, first + 1 - skip) end = max(start, first + room - skip) - return lines[offset:offset + room] + [_styled(f"{start}-{end} of {total - skip}", "dim")] + where = _styled(f"{start}-{end} of {total - skip}", "dim") + where.mark = ("scroll", "pager", total) + return lines[offset:offset + room] + [where] def _pager_starts(state: TuiState, items: list, width: int) -> list[int]: @@ -17273,6 +17494,7 @@ def _view_error(state: TuiState, width: int, height: int) -> tuple: first = max(0, min(state.focus.get("error_text", 0), len(text) - (room - 1))) state.focus["error_text"] = first text = _scrolled(text, first, room) + text[-1].mark = ("scroll", "error", 0) page = (TUI_ROUTES.get(state.pad, TUI_ROUTES["both"]).help["page"] or "PgUp/PgDn").split(", ")[0] hint += (f"{page} Scroll",) @@ -17449,14 +17671,94 @@ def tui_view(state: TuiState, cols: int, rows: int) -> list[str]: lines = [_styled(fit(f" RetroBIOS: {title}", cols), "head"), _styled("")] # A long line is drawn whole, the terminal folding it into the rows # after it (_text_lines): cut to the width, a copied path lost its end. - lines += [_styled(" " + line if line.style == "long" else fit(" " + line, cols), line.style) - for line in body[:height]] + for line in body[:height]: + drawn = _styled(" " + line if line.style == "long" else fit(" " + line, cols), + line.style) + drawn.mark = line.mark + lines.append(drawn) lines += [_styled("")] * (rows - 1 - len(lines)) # Never the last cell of the screen: a terminal may scroll when it is written. - lines.append(_styled(fit(" " + _hint(width, *hint), cols - 1), "hint")) + bar = _styled(fit(" " + _hint(width, *hint), cols - 1), "hint") + bar.mark = ("bar",) + lines.append(bar) return lines +class TuiHits(NamedTuple): + """What a click reaches on one drawn frame (tui_hits): each target is + (line, first column, column past the last, what it does), lines and + columns counted from 0. listing is (first row shown, rows shown, rows) + for a list taller than its room, scroll "pager" or "error" for a text + that scrolls.""" + + screen: str + help: bool + size: tuple[int, int] + targets: tuple + listing: tuple | None = None + scroll: str = "" + + def at(self, col: int, line: int) -> tuple | None: + return next((target for row, first, end, target in self.targets + if row == line and first <= col < end), None) + + +# The keys the bar's entries name, as a click on the entry presses them. A +# pair of keys (Left/Right, PgUp/PgDn) is no button: which one is meant +# cannot be told. +_BAR_CLICKS = { + "A/Enter": TuiKey("enter"), "A": TuiKey("enter"), "Enter": TuiKey("enter"), + "Start": TuiKey("enter"), "B/Esc": TuiKey("esc"), "B": TuiKey("esc"), + "Esc": TuiKey("esc"), "X/Space": TuiKey("char", " "), "X": TuiKey("char", " "), + "Space": TuiKey("char", " "), "Y/o": TuiKey("char", "o"), "Y": TuiKey("char", "o"), + "o": TuiKey("char", "o"), "/": TuiKey("char", "/"), "Ctrl-U": TuiKey("ctrl-u"), + "Ctrl-C": TuiKey("ctrl-c"), + # F1 and not ?, which the path screen types into the path. + "?": TuiKey("f1"), +} +_BAR_ENTRY = re.compile(r"\S+(?: \S+)*") + + +def _bar_click(state: TuiState, name: str) -> TuiKey | None: + """The key a bar entry's name stands for, on the route the bar names.""" + route = TUI_ROUTES.get(state.pad) + if route is not None and name not in _BAR_CLICKS: + name = next((key for key, mine in route.bar.items() if mine == name), name) + return _BAR_CLICKS.get(name) + + +def tui_hits(state: TuiState, lines: list[str]) -> TuiHits: + """The targets of the frame tui_view drew: a row of the list across + the whole width, its text or not, each entry of the bar that names a + key, and the line saying which lines are in view.""" + cols = max([state.cols, *(cell_width(str(line)) for line in lines)]) + targets: list[tuple] = [] + shown: list[int] = [] + listed = None + scroll = "" + for number, line in enumerate(lines): + mark = getattr(line, "mark", None) + if not mark: + continue + if mark[0] == "row": + targets.append((number, 0, cols, mark)) + shown.append(mark[1]) + elif mark[0] == "scroll": + targets.append((number, 0, cols, mark)) + if mark[1] == "list": + listed = mark[2] + else: + scroll = mark[1] + elif mark[0] == "bar" and not state.help: + for entry in _BAR_ENTRY.finditer(str(line)): + key = _bar_click(state, entry.group().split(" ", 1)[0]) + if key is not None: + targets.append((number, entry.start(), entry.end(), ("key", key))) + rows = (min(shown), len(shown), listed) if listed is not None and shown else None + return TuiHits(state.screen, state.help, (state.cols, state.rows), tuple(targets), + rows, scroll) + + def _setup_label(plat: str, path: Path) -> str: system = detected_os(plat, path) name = display_name(plat) @@ -17854,6 +18156,18 @@ class _TuiTerminal: self.heard = 0.0 self.frame: list[tuple[str, str]] = [] self.entered = False + # Whether clicks may be asked for here (tui_mouse_blocker), and + # whether they are now: off on a screen whose text is copied. + self.mouse_allowed = not tui_mouse_blocker(stdin, stdout) + self.mouse = False + + def set_mouse(self, on: bool) -> None: + """Ask for clicks or give them back to the terminal, written only + when that changes.""" + on = on and getattr(self, "mouse_allowed", False) and self.entered + if on != getattr(self, "mouse", False): + self.mouse = on + self.write(_MOUSE_ON if on else _MOUSE_OFF) def enter(self) -> None: if os.name != "nt": @@ -17881,6 +18195,9 @@ class _TuiTerminal: # the cursor are as they were, nothing is written over them. if getattr(self, "entered", True): self.entered = False + # The mouse modes go with the screen (_SCREEN_OFF), and come + # back with the next frame once entered again. + self.mouse = False self.write(_SCREEN_OFF) finally: if self.saved is not None: @@ -18263,7 +18580,12 @@ def run_tui(args: argparse.Namespace) -> int: state.cols, state.rows = cols, rows terminal.frame = [] state.now = time.monotonic() - terminal.draw(tui_view(state, cols, rows), cols) + lines = tui_view(state, cols, rows) + # A click is read against the frame it was made on. + state.hits = tui_hits(state, lines) + # Before the frame: a frame on screen takes clicks as it shows. + terminal.set_mouse(tui_wants_mouse(state, lines)) + terminal.draw(lines, cols) for key in terminal.keys(TUI_FRAME): if key.name == "ctrl-z": # ISIG is off, so Ctrl-Z comes as a key: it stops what diff --git a/install.sh b/install.sh index a53481c67..629d48f74 100755 --- a/install.sh +++ b/install.sh @@ -18,7 +18,7 @@ esac TEMP_INSTALLER="" TEMP_DIRECTORY="" DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py" -DEFAULT_INSTALL_SHA256="825b55c17403287319a0c7d6e118e34d1bbf21cf0e6e66029c6c7eb767d2e0cb" +DEFAULT_INSTALL_SHA256="7757b36db5beb3cbeb3717e0736db630237e87da5189a14d5092e679b69156af" MAX_INSTALLER_BYTES=2097152 cleanup() { diff --git a/install/launchers/index.json b/install/launchers/index.json index 22a20653b..0f5e5493c 100644 --- a/install/launchers/index.json +++ b/install/launchers/index.json @@ -27,8 +27,8 @@ { "dest": "roms/ports/retrobios/install.py", "repo_path": "install.py", - "size": 840737, - "sha256": "825b55c17403287319a0c7d6e118e34d1bbf21cf0e6e66029c6c7eb767d2e0cb", + "size": 854609, + "sha256": "7757b36db5beb3cbeb3717e0736db630237e87da5189a14d5092e679b69156af", "executable": false }, { @@ -71,8 +71,8 @@ "muos": { "archive": { "dest": "ARCHIVE/RetroBIOS.muxapp", - "size": 893286, - "sha256": "d463dc4f1203733a0b4932d90a659c03b91701f27a6da7b01becb69f05dab83c" + "size": 907158, + "sha256": "15c404a5dfb8d084caa11843d3969e7f0222f434c9b2320b04a0d89ca7336f21" }, "members": [ { @@ -92,8 +92,8 @@ { "name": "RetroBIOS/install.py", "repo_path": "install.py", - "size": 840737, - "sha256": "825b55c17403287319a0c7d6e118e34d1bbf21cf0e6e66029c6c7eb767d2e0cb", + "size": 854609, + "sha256": "7757b36db5beb3cbeb3717e0736db630237e87da5189a14d5092e679b69156af", "executable": false }, { @@ -166,8 +166,8 @@ { "dest": ".config/modules/retrobios/install.py", "repo_path": "install.py", - "size": 840737, - "sha256": "825b55c17403287319a0c7d6e118e34d1bbf21cf0e6e66029c6c7eb767d2e0cb", + "size": 854609, + "sha256": "7757b36db5beb3cbeb3717e0736db630237e87da5189a14d5092e679b69156af", "executable": false }, { diff --git a/schemas/emulator.schema.json b/schemas/emulator.schema.json index cada7d28d..d1d2b4097 100644 --- a/schemas/emulator.schema.json +++ b/schemas/emulator.schema.json @@ -63,6 +63,33 @@ } } } + }, + { + "comment": "A profile whose code states no version says so with version_basis kind none and a null core_version, never a placeholder.", + "if": { + "properties": { + "version_basis": { + "properties": { + "kind": { + "const": "none" + } + }, + "required": [ + "kind" + ] + } + }, + "required": [ + "version_basis" + ] + }, + "then": { + "properties": { + "core_version": { + "type": "null" + } + } + } } ], "properties": { @@ -155,11 +182,50 @@ ] }, "core_version": { - "type": [ - "string", - "number", - "object", - "null" + "description": "The version of the code at the pin, read where version_basis says: the string the program states, git describe's form of the nearest tag, or the package read. Never a branch or VCS name (Git, SVN, master, latest, dev, unknown). null when version_basis is kind none. An object keys it by build mode, like source.", + "oneOf": [ + { + "type": "string", + "pattern": "^(?!([Gg][Ii][Tt]|[Ss][Vv][Nn]|[Uu][Nn][Kk][Nn][Oo][Ww][Nn]|[Mm][Aa][Ss][Tt][Ee][Rr]|[Mm][Aa][Ii][Nn]|[Ll][Aa][Tt][Ee][Ss][Tt]|[Dd][Ee][Vv]|[Hh][Ee][Aa][Dd])([\\s(]|$)).*\\S" + }, + { + "type": "null" + }, + { + "type": "object", + "minProperties": 1, + "additionalProperties": { + "oneOf": [ + { + "type": "string", + "pattern": "^(?!([Gg][Ii][Tt]|[Ss][Vv][Nn]|[Uu][Nn][Kk][Nn][Oo][Ww][Nn]|[Mm][Aa][Ss][Tt][Ee][Rr]|[Mm][Aa][Ii][Nn]|[Ll][Aa][Tt][Ee][Ss][Tt]|[Dd][Ee][Vv]|[Hh][Ee][Aa][Dd])([\\s(]|$)).*\\S" + }, + { + "type": "null" + } + ] + } + } + ] + }, + "version_basis": { + "description": "Where core_version is read, so a tool reads it again at any pin. An object keyed by build mode when core_version is.", + "oneOf": [ + { + "$ref": "#/$defs/version_basis" + }, + { + "type": "object", + "minProperties": 1, + "not": { + "required": [ + "kind" + ] + }, + "additionalProperties": { + "$ref": "#/$defs/version_basis" + } + } ] }, "alias_of": { @@ -963,5 +1029,188 @@ "type": "string", "description": "Repository carrying the same tree, consulted after source and upstream. The only thing that keeps a profile checkable once its own forge is withdrawn or its host stops resolving." } + }, + "$defs": { + "version_basis": { + "type": "object", + "additionalProperties": false, + "required": [ + "kind" + ], + "properties": { + "kind": { + "enum": [ + "file", + "tag", + "alias", + "package", + "none", + "unverified" + ], + "description": "file: a pattern in one file at the pin. tag: the nearest tag in the pin's history. alias: the version of the profile it aliases. package: an artefact read outside any source tree. none: the code at the pin states no version and no tag reaches it. unverified: no reading could be made, for the reason why gives. core_version stays as written, unconfirmed." + }, + "why": { + "enum": [ + "no_pin", + "host_unsupported", + "host_gone", + "host_unreachable", + "pin_off_branch", + "no_artifact", + "no_source" + ], + "description": "Why a basis is unverified: no pinned commit, a host the tools cannot read, a forge gone, a forge that did not answer, a pin on another branch than the build the profile describes, no build or package named as read, no source declared." + }, + "repo": { + "enum": [ + "source", + "upstream", + "source_mirror" + ], + "description": "The declared repository the version describes, pinned by source_commit (source, source_mirror) or upstream_commit. Default source." + }, + "url": { + "type": "string", + "format": "uri", + "description": "kind file: a repository outside the profile's own, read at commit (the package file of a build a platform ships). kind package: where the artefact was obtained." + }, + "commit": { + "type": "string", + "pattern": "^[0-9a-f]{7,40}$", + "description": "The revision of url the file is read at." + }, + "path": { + "type": "string", + "minLength": 1, + "description": "File read at the pin." + }, + "pattern": { + "type": "string", + "minLength": 1, + "description": "Regular expression, multiline, whose groups hold the version." + }, + "format": { + "type": "string", + "pattern": "\\{\\d+", + "description": "How the groups are laid out, {1}.{2} or {4:02d}. Default: group 1." + }, + "match": { + "type": "string", + "minLength": 1, + "description": "Glob a tag must fit to count, as git describe --match takes it." + }, + "tag": { + "type": "string", + "minLength": 1, + "description": "The nearest tag in the pin's history." + }, + "distance": { + "type": "integer", + "minimum": 0, + "description": "Commits the pin has that the tag lacks." + }, + "of": { + "type": "string", + "minLength": 1, + "description": "The profile this one aliases." + }, + "artifact": { + "type": "string", + "minLength": 1, + "description": "The package, binary or archive the version was read from." + } + }, + "allOf": [ + { + "if": { + "properties": { + "kind": { + "const": "file" + } + } + }, + "then": { + "required": [ + "path", + "pattern" + ] + } + }, + { + "if": { + "properties": { + "kind": { + "const": "tag" + } + } + }, + "then": { + "required": [ + "tag", + "distance" + ] + } + }, + { + "if": { + "properties": { + "kind": { + "const": "alias" + } + } + }, + "then": { + "required": [ + "of" + ] + } + }, + { + "if": { + "properties": { + "kind": { + "const": "package" + } + } + }, + "then": { + "required": [ + "artifact" + ] + } + }, + { + "if": { + "properties": { + "kind": { + "const": "file" + } + }, + "required": [ + "url" + ] + }, + "then": { + "required": [ + "commit" + ] + } + }, + { + "if": { + "properties": { + "kind": { + "const": "unverified" + } + } + }, + "then": { + "required": [ + "why" + ] + } + } + ] + } } } diff --git a/scripts/generate_site.py b/scripts/generate_site.py index 64c7affda..f8f5fee75 100644 --- a/scripts/generate_site.py +++ b/scripts/generate_site.py @@ -2511,7 +2511,9 @@ def _emulator_description(markdown: str, key: str, title: str, intro: str) -> st row = {name: _plain_markdown(value) for name, value in re.findall( r"^\| (Type|Classification|Version) \| (.+?) \|$", markdown, re.M)} kind = row.get("Classification") or row.get("Type") or "emulator" - version = row.get("Version", "") + # The cell goes on to say where the version is read: the intro + # keeps the version alone. + version = row.get("Version", "").split(", ")[0] known = f", version {version}" if version and version[0].isdigit() else "" intro = f"{title}: {kind.lower()}{known}." elif title not in intro: @@ -7993,7 +7995,8 @@ def emulator_romset(profile: dict) -> str: version = str(profile.get("core_version") or "") if profile.get("mame_version"): return f"MAME {profile['mame_version']}" - if "MAME" in emulator and _MAME_RELEASE.match(version): + # HBMAME's sets are its own homebrew sets, whatever MAME it is based on. + if "MAME" in emulator and "HBMAME" not in emulator and _MAME_RELEASE.match(version): return f"MAME {version}" if emulator.startswith("FinalBurn Neo") and version: return f"FinalBurn Neo {version}" @@ -8002,6 +8005,114 @@ def emulator_romset(profile: dict) -> str: return "" +def _version_said(value: object, basis: dict) -> str: + """One build's version and where the profile reads it.""" + kind = basis.get("kind") + if kind == "none": + return "none stated in the source" + if value is None: + if kind == "unverified": + return f"unknown: {_UNVERIFIED.get(str(basis.get('why')), 'unread')}" + return "none published" + value = str(value) + if kind == "file": + return f"{value}, stated in `{basis.get('path')}`" + if kind == "tag": + distance = int(basis.get("distance") or 0) + if not distance: + return f"{value}, the tag at this revision" + return f"{value}, {distance} commit{'s' if distance != 1 else ''} after tag `{basis.get('tag')}`" + if kind == "package": + return f"{value}, read from {basis.get('artifact')}" + if kind == "unverified": + return f"{value}, not confirmed: {_UNVERIFIED.get(str(basis.get('why')), 'unread')}" + return value + + +# Why a profile's version could not be read, said to a reader. +_UNVERIFIED = { + "no_pin": "no revision recorded", + "host_unsupported": "its host cannot be read", + "host_gone": "its source is gone", + "host_unreachable": "its host did not answer", + "pin_off_branch": "its recorded revision is not the build described", + "no_artifact": "no build recorded as read", + "no_source": "no source declared", +} + + +def version_markdown(profile: dict) -> str: + """The Version cell: core_version and where version_basis reads it. + + A null version said "none published" whether the code states none or + nobody looked. Keyed by build mode like source, each build is named, + where the page printed the dict's Python repr. + """ + if "core_version" not in profile and not profile.get("version_basis"): + return "unknown" + value = profile.get("core_version") + basis = profile.get("version_basis") if isinstance(profile.get("version_basis"), dict) else {} + if isinstance(value, dict) or (basis and "kind" not in basis): + values = value if isinstance(value, dict) else {} + modes = list(dict.fromkeys([*values, *basis])) + return ", ".join( + f"{_version_said(values.get(mode), basis.get(mode) or {})} ({mode})" + for mode in modes + ) + return _version_said(value, basis) + + +ROMSET_FAQ_PAGE = Path(WIKI_SRC_DIR) / "technical-faq.md" +_ROMSET_BLOCK = re.compile( + r"(<!-- generated: romsets -->\n)(.*?)(<!-- /generated: romsets -->)", re.S) + + +def _retroarch_label(profile: dict) -> str: + """"Arcade (MAME 2003)" gives "MAME 2003", "Arcade (FinalBurn Neo) + (Neo-Geo)" gives "FinalBurn Neo (Neo-Geo)".""" + inner = str(profile.get("display_name") or profile.get("emulator") or "").split("(", 1)[-1] + return inner.replace(")", "", 1).strip() + + +def romset_table(profiles: dict) -> list[str]: + """The FAQ's arcade table: each MAME and FinalBurn libretro core and the + romset its profile reads at its pin. + + Written by hand, it told readers to collect MAME 0.160 sets for a core + whose src/version.c states 0.159, and FinalBurn Neo 1.0.0.2 for a source + at 1.0.0.03. A core whose name gives its version (Recalbox's MAME 0.258) + needs no row. + """ + rows: dict[str, list[str]] = {} + for key, profile in sorted(profiles.items()): + if not re.match(r"(mame|fbneo|fbalpha)", key) or \ + "libretro" not in str(profile.get("type", "")): + continue + romset = emulator_romset(profile) + label = _retroarch_label(profile) + if not romset or romset.split(" ", 1)[1].lstrip("v") in label: + continue + rows.setdefault(romset, []).append(label) + + def order(romset: str) -> tuple: + family = 0 if romset.startswith("MAME") else 1 if romset.startswith("FB Alpha") else 2 + numbers = tuple(int(n) for n in re.findall(r"\d+", romset.split(" (", 1)[0])) + return family, numbers + + lines = ["| Emulator, as RetroArch names it | Sets from |", "|---|---|"] + for romset in sorted(rows, key=order): + lines.append(f"| {', '.join(sorted(rows[romset]))} | {romset} |") + return lines + + +def with_romset_table(page: str, profiles: dict) -> str: + """The FAQ page with its romset table read from the profiles.""" + table = "\n".join(romset_table(profiles)) + "\n" + if not _ROMSET_BLOCK.search(page): + raise ValueError(f"{ROMSET_FAQ_PAGE}: no romsets block to write the table in") + return _ROMSET_BLOCK.sub(lambda m: f"{m.group(1)}{table}{m.group(3)}", page, count=1) + + def _render_metadata_rows(profile: dict) -> list[str]: """Scalar profile fields, one table row each. @@ -9174,15 +9285,7 @@ def emulator_pages( upstream_raw = profile.get("upstream", "") upstream_none = "upstream" in profile and upstream_raw is None upstream = str(upstream_raw) if isinstance(upstream_raw, str) else "" - version_raw = profile.get("core_version", "unknown") - if version_raw is None: - version = "none published" - elif isinstance(version_raw, dict): - # Keyed by build mode like source: each build's version, named, - # where the page printed the dict's Python repr. - version = ", ".join(f"{v} ({mode})" for mode, v in version_raw.items() if v) - else: - version = version_raw + version = version_markdown(profile) profiled = profile.get("profiled_date", "unknown") systems = profile.get("systems", []) cores = profile.get("cores", [name]) @@ -11652,6 +11755,11 @@ def _generate(args: argparse.Namespace) -> None: wiki_dest = docs / "wiki" wiki_dest.mkdir(parents=True, exist_ok=True) wiki_src = Path(WIKI_SRC_DIR) + # The romset table is the profiles' versions, never typed: the source + # page is rewritten before it is copied, as the README is. + faq = _REPO_ROOT / ROMSET_FAQ_PAGE + if faq.is_file(): + write_if_changed(str(faq), with_romset_table(faq.read_text(encoding="utf-8"), profiles)) if wiki_src.is_dir(): for src_file in wiki_src.glob("*.md"): shutil.copy2(src_file, wiki_dest / src_file.name) diff --git a/scripts/profile_sync.py b/scripts/profile_sync.py index e42d99b61..741ac22b7 100644 --- a/scripts/profile_sync.py +++ b/scripts/profile_sync.py @@ -31,6 +31,7 @@ import yaml sys.path.insert(0, os.path.dirname(__file__)) import upstream +import version_basis from common import ( _norm_system_id, github_token, @@ -2670,6 +2671,129 @@ def apply_edit(path: Path, new_text: str, expected: dict) -> None: raise YamlWriteError(f"{path}: structure changed beyond the intended field") +# Key order of a written version_basis, as a reader expects it. +_BASIS_ORDER = ("kind", "why", "repo", "url", "commit", "path", "pattern", "format", + "match", "tag", "distance", "of", "artifact") + + +def _top_block(lines: list[str], key: str) -> tuple[int, int] | None: + """Line span of a top-level key and the indented lines under it.""" + indices = _top_level_indices(lines, key) + if not indices: + return None + if len(indices) > 1: + raise YamlWriteError(f"{key}: expected one top-level line, found {len(indices)}") + end = indices[0] + 1 + while end < len(lines) and (lines[end].startswith((" ", "\t")) or not lines[end].strip()): + end += 1 + # Blank lines closing the block belong to the document, not to it. + while end > indices[0] + 1 and not lines[end - 1].strip(): + end -= 1 + return indices[0], end + + +def _render_version(value: object) -> list[str]: + if isinstance(value, dict): + return ["core_version:"] + [ + f" {mode}: {'null' if v is None else _double_quoted(str(v))}" + for mode, v in value.items() + ] + return [f"core_version: {'null' if value is None else _double_quoted(str(value))}"] + + +def _render_basis(basis: dict) -> list[str]: + def ordered(entry: dict) -> dict: + rank = {key: i for i, key in enumerate(_BASIS_ORDER)} + return dict(sorted(entry.items(), key=lambda item: rank.get(item[0], len(rank)))) + + def scalar(value: object) -> str: + # Every string quoted: a tag 2407 or 0.10 read back as a number. A + # pattern keeps its backslashes readable in single quotes. + if isinstance(value, bool) or not isinstance(value, str): + return str(value).lower() if isinstance(value, bool) else str(value) + if "\\" in value or '"' in value: + return "'" + value.replace("'", "''") + "'" + return _double_quoted(value) + + def block(entry: dict, indent: str) -> list[str]: + # kind, why and repo are words of the schema's enums, written bare. + return [f"{indent}{key}: {value if key in ('kind', 'why', 'repo') else scalar(value)}" + for key, value in ordered(entry).items()] + + if "kind" in basis: + return ["version_basis:", *block(basis, " ")] + lines = ["version_basis:"] + for mode, entry in basis.items(): + lines += [f" {mode}:", *block(entry, " ")] + return lines + + +def set_version_fields(text: str, version: object, basis: dict | None) -> str: + """Rewrite core_version and version_basis, version_basis right after it.""" + lines = text.splitlines() + span = _top_block(lines, "core_version") + rendered = _render_version(version) + if span is None: + anchor = _top_block(lines, "upstream_commit") or _top_block(lines, "source_commit") \ + or _top_block(lines, "profiled_date") or _top_block(lines, "upstream") \ + or _top_block(lines, "source") or _top_block(lines, "alias_of") \ + or _top_block(lines, "type") + if anchor is None: + raise YamlWriteError("core_version: no line to write it after") + lines[anchor[1]:anchor[1]] = rendered + else: + lines[span[0]:span[1]] = rendered + if basis is not None: + old = _top_block(lines, "version_basis") + if old is not None: + del lines[old[0]:old[1]] + after = _top_block(lines, "core_version") + lines[after[1]:after[1]] = _render_basis(basis) + return "\n".join(lines) + ("\n" if text.endswith("\n") else "") + + +def apply_readings(document: dict, readings: list) -> tuple[object, dict | None]: + """core_version and version_basis as the readings state them. + + A reading that could not be made leaves its build mode as written. + """ + version = document.get("core_version") + basis = document.get("version_basis") + basis = dict(basis) if isinstance(basis, dict) else None + if isinstance(version, dict): + version = dict(version) + for reading in readings: + if reading.status not in (version_basis.MATCH, version_basis.DRIFT): + continue + if reading.mode: + if not isinstance(version, dict): + version = {} + version[reading.mode] = reading.read + else: + version = reading.read + if reading.updates and basis is not None: + target = basis if not reading.mode else dict(basis.get(reading.mode) or {}) + target.update(dict(reading.updates)) + if reading.mode: + basis[reading.mode] = target + return version, basis + + +def write_version(path: Path, readings: list) -> bool: + """Set core_version (and a tag basis' tag and distance) from the readings.""" + text = path.read_text(encoding="utf-8") + document = yaml.safe_load(text) + version, basis = apply_readings(document, readings) + if version == document.get("core_version") and basis == document.get("version_basis"): + return False + expected = dict(document) + expected["core_version"] = version + if basis is not None: + expected["version_basis"] = basis + apply_edit(path, set_version_fields(text, version, basis), expected) + return True + + def backfill_commit(path: Path, sha: str) -> bool: """Insert source_commit after profiled_date. False when already present.""" text = path.read_text(encoding="utf-8") @@ -3313,9 +3437,15 @@ def _needs_review(report: ProfileReport, accept_changed: bool) -> bool: def bump_commit( - path: Path, report: ProfileReport, accept_changed: bool = False + path: Path, report: ProfileReport, accept_changed: bool = False, + cache_dir: str = DEFAULT_CACHE, offline: bool = False, ) -> bool: - """Advance source_commit to HEAD when nothing needs a read again.""" + """Advance source_commit to HEAD when nothing needs a read again. + + core_version moves with the pin, read again from version_basis at the + new revision. Four bulk advances moved 295 pins and no version: an + advance whose version cannot be read is refused. + """ if _needs_review(report, accept_changed): return False text = path.read_text(encoding="utf-8") @@ -3375,10 +3505,33 @@ def bump_commit( new_text = _set_pin( new_text, document, "upstream_commit", report.upstream_head, "source_commit" ) + readings = version_basis.check(expected, cache_dir, offline, recompute=True) + refused = version_refusal(readings) + if refused: + print(f"{path.stem}: {refused}, its pin is not advanced", file=sys.stderr) + return False + version, basis = apply_readings(expected, readings) + if version != expected.get("core_version") or basis != expected.get("version_basis"): + new_text = set_version_fields(new_text, version, basis) + expected["core_version"] = version + if basis is not None: + expected["version_basis"] = basis apply_edit(path, new_text, expected) return True +def version_refusal(readings: list) -> str | None: + """Why the version at a new pin cannot be stated, or None.""" + for reading in readings: + if reading.status == version_basis.NO_BASIS: + return "no version_basis says where its version is read" + if reading.status == version_basis.UNREADABLE: + return f"core_version cannot be read at the new pin: {reading.where}" + if reading.status == version_basis.UNCHECKED: + return f"core_version is {reading.where}, not read from the code at a pin" + return None + + def pins_changed(before: dict, after: dict) -> list[str]: """The pin fields whose value a write changed.""" return [ @@ -3996,6 +4149,16 @@ def build_parser() -> argparse.ArgumentParser: "--check-version", action="store_true", help="compare core_version with the latest tag and release", ) + parser.add_argument( + "--verify-version", action="store_true", + help="read core_version again from version_basis at the pin and " + "exit 1 when the code states another", + ) + parser.add_argument( + "--set-version", action="store_true", + help="write core_version from version_basis at the pin, the nearest " + "tag asked of git again", + ) parser.add_argument( "--detect-new-files", action="store_true", help="name files upstream loads that the profile does not list", @@ -4284,7 +4447,8 @@ def _apply_writes( applied = [] if args.rebase_refs and not report.skipped: applied = rebase_refs(target, report, args.accept_changed) - moved = bump_commit(target, report, args.accept_changed) + moved = bump_commit(target, report, args.accept_changed, + args.cache_dir, args.offline) if args.rebase_refs and applied and not moved: keyed = any(isinstance(profile.get(f), dict) for f in ("source_commit", "upstream_commit")) reason = ( @@ -4723,6 +4887,32 @@ def _print_triage( def _refuse_flag_combinations(args: argparse.Namespace) -> None: """Exit on a flag the chosen mode would not apply, before any request.""" + if args.verify_version or args.set_version: + ignored = [ + flag for flag, on in ( + ("--verify-version", args.verify_version and args.set_version), + ("--markdown", args.markdown), + ("--fetch-plan", args.fetch_plan), + ("--triage", args.triage), + ("--strict", args.strict), + ("--check-version", args.check_version), + ("--detect-new-files", args.detect_new_files), + ("--watch-hashes", args.watch_hashes), + ("--full-diff", args.full_diff), + ("--tree-diff", args.tree_diff), + ("--backfill-commits", args.backfill_commits), + ("--rebase-refs", args.rebase_refs), + ("--attribute-refs", args.attribute_refs), + ("--bump-commit", args.bump_commit), + ("--realign-prose", args.realign_prose), + ("--accept-changed", args.accept_changed), + ("--dry-run", args.dry_run and not args.set_version), + ) if on + ] + if ignored: + mode = "--set-version" if args.set_version else "--verify-version" + print(f"{mode} does not apply {', '.join(ignored)}", file=sys.stderr) + raise SystemExit(1) if args.fresh and args.offline: print("--fresh asks the forges again, which --offline forbids.", file=sys.stderr) raise SystemExit(1) @@ -4809,6 +4999,63 @@ def _refuse_flag_combinations(args: argparse.Namespace) -> None: raise SystemExit(1) +def _version_selection(args: argparse.Namespace, profiles: dict) -> dict: + """--all reaches the alias and test profiles too: each states a version.""" + if args.all and not (args.system or args.type_ or args.stale_before or args.limit): + return dict(sorted(profiles.items())) + return select_profiles(profiles, args) + + +def format_reading(name: str, reading: version_basis.Reading) -> str: + mode = f"[{reading.mode}] " if reading.mode else "" + kind = f"{reading.kind} " if reading.kind else "" + if reading.status == version_basis.DRIFT: + said = f"declared {reading.declared}, code {reading.read}" + elif reading.status == version_basis.MATCH: + said = str(reading.read) + else: + said = f"declared {reading.declared}" + return f"{name}: {mode}{reading.status} {said} ({kind}{reading.where})" + + +def run_versions(args: argparse.Namespace, profiles: dict) -> None: + """--verify-version and --set-version: core_version against the code.""" + selected = _version_selection(args, profiles) + if args.set_version and not args.dry_run and not args.force: + _refuse_dirty_tree(args.emulators_dir, list(selected)) + counts: Counter = Counter() + rows = [] + failed = False + for name, profile in selected.items(): + readings = version_basis.check( + profile, args.cache_dir, args.offline, profiles, recompute=args.set_version + ) + for reading in readings: + counts[reading.status] += 1 + rows.append({"profile": name, **asdict(reading)}) + if not args.as_json and (not args.changed_only or reading.status != version_basis.MATCH): + print(format_reading(name, reading)) + if args.set_version: + path = Path(args.emulators_dir) / f"{name}.yml" + if args.dry_run: + continue + try: + if write_version(path, readings): + print(f"{name}: core_version written") + except YamlWriteError as exc: + print(f"{name}: write refused: {exc}", file=sys.stderr) + failed = True + elif any(r.status in version_basis.FAILING for r in readings): + failed = True + if args.as_json: + print(json.dumps(rows, indent=2)) + else: + print(", ".join(f"{count} {status}" for status, count in sorted(counts.items())), + file=sys.stderr) + if failed: + raise SystemExit(1) + + def main() -> None: """Build one report per selected profile, then apply writes and output.""" args = build_parser().parse_args() @@ -4818,6 +5065,9 @@ def main() -> None: # trzy/Supermodel and VICE read as behind their real HEAD. upstream.MOVING_TTL = 0 profiles = load_emulator_profiles(args.emulators_dir, skip_aliases=False) + if args.verify_version or args.set_version: + run_versions(args, profiles) + return selected = select_profiles(profiles, args) _check_quota(len(selected), args.offline) diff --git a/scripts/scraper/_hash_merge.py b/scripts/scraper/_hash_merge.py index 1642357f5..4fe3cc93d 100644 --- a/scripts/scraper/_hash_merge.py +++ b/scripts/scraper/_hash_merge.py @@ -158,7 +158,12 @@ def merge_fbneo_profile( profile = _load_yaml(profile_path) hashes = _load_json(hashes_path) - profile["core_version"] = hashes.get("version", profile.get("core_version")) + # core_version stays as written: it is the version of the code at the + # profile's own pin, read through version_basis (profile_sync + # --set-version). The hashes come from finalburnneo/FBNeo's tip, a + # revision the libretro/FBNeo pin does not name: writing its version + # left fbneo, fbneo_cps12 and fbneo_neogeo on a release their pin + # never was. files = profile.get("files", []) archive_files, non_archive = _split_files(files, lambda f: "archive" in f) @@ -1060,17 +1065,16 @@ def _backup_and_write_fbneo(path: str, data: dict, hashes: dict) -> None: """Write merged FBNeo profile using text-based patching. FBNeo profiles have individual ROM entries with archive: field. - Patches core_version, the content values of existing entries that - changed, and appends new ROM entries. Advancing core_version alone left - a profile claiming a release whose crc32 it did not carry. Comments and - curated source_refs stay as written. + Patches the content values of existing entries that changed and + appends new ROM entries. core_version is the pin's, never written here. + Comments and curated source_refs stay as written. """ p = Path(path) backup = p.with_suffix(PROFILE_BACKUP_SUFFIX) shutil.copy2(p, backup) original = p.read_text(encoding="utf-8") - patched = _patch_core_version(original, data.get("core_version", "")) + patched = original # Identify new ROM entries by comparing parsed data keys, not text search existing_data = yaml_load(original) or {} diff --git a/scripts/scraper/fbneo_hash_scraper.py b/scripts/scraper/fbneo_hash_scraper.py index b641be10c..17ac95a43 100644 --- a/scripts/scraper/fbneo_hash_scraper.py +++ b/scripts/scraper/fbneo_hash_scraper.py @@ -11,6 +11,7 @@ import argparse import json import logging import os +import re import shutil import subprocess import sys @@ -20,7 +21,7 @@ from typing import Any import yaml -from common import github_token, source_yaml_paths, write_text_atomic, yaml_load +from common import source_yaml_paths, write_text_atomic, yaml_load from scripts.scraper._hash_merge import compute_diff, merge_fbneo_profile from scripts.scraper.fbneo_parser import parse_fbneo_source_tree @@ -51,7 +52,7 @@ def _is_cache_fresh() -> bool: def _sparse_clone() -> None: - """Sparse clone FBNeo repo, checking out only src/burn/drv.""" + """Sparse clone FBNeo repo: src/burn/drv, and in cone mode src/burn/version.h.""" if CLONE_DIR.exists(): shutil.rmtree(CLONE_DIR) @@ -74,7 +75,7 @@ def _sparse_clone() -> None: ) subprocess.run( - ["git", "sparse-checkout", "set", "src/burn/drv", "src/burner/resource.h"], + ["git", "sparse-checkout", "set", "src/burn/drv"], cwd=CLONE_DIR, check=True, capture_output=True, @@ -82,31 +83,28 @@ def _sparse_clone() -> None: ) +# src/burn/version.h, as the libretro core prints it: "v%x.%x.%x.%02x" of +# the BCD BURN_VERSION, so VER_ALPHA 3 reads 1.0.0.03. FBNeo bumps this file +# without tagging: the last tag (v1.0.0.02) was 9 337 commits behind it. +_VERSION_H = re.compile( + r"#define\s+VER_MAJOR\s+(\d+)\s+#define\s+VER_MINOR\s+(\d+)\s+" + r"#define\s+VER_BETA\s+(\d+)\s+#define\s+VER_ALPHA\s+(\d+)" +) + + +def version_from_header(text: str) -> str: + """The version src/burn/version.h states.""" + found = _VERSION_H.search(text) + if not found: + raise RuntimeError("src/burn/version.h states no VER_MAJOR..VER_ALPHA") + major, minor, beta, alpha = (int(group) for group in found.groups()) + return f"v{major}.{minor}.{beta}.{alpha:02d}" + + def _extract_version() -> tuple[str, str]: - """Extract version tag and commit SHA from the cloned repo. - - Returns (version, commit_sha). Falls back to resource.h if no tag. - """ - result = subprocess.run( - ["git", "describe", "--tags", "--abbrev=0"], - cwd=CLONE_DIR, - capture_output=True, - text=True, - ) - - # Prefer real version tags over pseudo-tags like "latest" - version = "unknown" - if result.returncode == 0: - tag = result.stdout.strip() - if tag and tag != "latest": - version = tag - # Fallback: resource.h - if version == "unknown": - version = _version_from_resource_h() - # Last resort: use GitHub API for latest real release tag - if version == "unknown": - version = _version_from_api() - + """The version the cloned source states, and its commit.""" + header = CLONE_DIR / "src" / "burn" / "version.h" + version = version_from_header(header.read_text(encoding="utf-8", errors="replace")) sha_result = subprocess.run( ["git", "rev-parse", "HEAD"], cwd=CLONE_DIR, @@ -114,49 +112,7 @@ def _extract_version() -> tuple[str, str]: text=True, check=True, ) - commit = sha_result.stdout.strip() - - return version, commit - - -def _version_from_api() -> str: - """The latest real release tag, or an error: "unknown" was written as - core_version and cached for a day.""" - import json as json_mod - import urllib.error - import urllib.request - - headers = {"User-Agent": "retrobios-scraper/1.0"} - token = github_token() - if token: - headers["Authorization"] = f"Bearer {token}" - req = urllib.request.Request( - "https://api.github.com/repos/finalburnneo/FBNeo/tags?per_page=10", headers=headers - ) - try: - with urllib.request.urlopen(req, timeout=10) as resp: - tags = json_mod.loads(resp.read()) - except (urllib.error.URLError, OSError, ValueError) as exc: - raise RuntimeError(f"cannot determine the FBNeo version: {exc}") from exc - for tag in tags: - if tag["name"] != "latest" and tag["name"].startswith("v"): - return tag["name"] - raise RuntimeError("cannot determine the FBNeo version: no tag, resource.h or release") - - -def _version_from_resource_h() -> str: - """Fallback: parse VER_FULL_VERSION_STR from resource.h.""" - resource_h = CLONE_DIR / "src" / "burner" / "resource.h" - if not resource_h.exists(): - return "unknown" - - text = resource_h.read_text(encoding="utf-8", errors="replace") - for line in text.splitlines(): - if "VER_FULL_VERSION_STR" in line: - parts = line.split('"') - if len(parts) >= 2: - return parts[1] - return "unknown" + return version, sha_result.stdout.strip() def _cleanup() -> None: diff --git a/scripts/scraper/mame_hash_scraper.py b/scripts/scraper/mame_hash_scraper.py index 0d2e8411d..bbdc38d08 100644 --- a/scripts/scraper/mame_hash_scraper.py +++ b/scripts/scraper/mame_hash_scraper.py @@ -467,6 +467,13 @@ def release_profile( "source_commit": source_commit, "upstream_commit": upstream_commit, "core_version": version, + # Where profile_sync reads it again: the makefile of the libretro/mame + # tree the platform builds, at source_commit. + "version_basis": { + "kind": "file", + "path": "makefile", + "pattern": '#define BARE_BUILD_VERSION "([^"]+)"', + }, "display_name": f"Arcade (MAME {version})", "cores": cores, "built_by": built_by, diff --git a/scripts/upstream.py b/scripts/upstream.py index c2cb95a0d..9892cded2 100644 --- a/scripts/upstream.py +++ b/scripts/upstream.py @@ -12,6 +12,7 @@ import http.client import json import os import socket +import subprocess import tempfile import time import urllib.error @@ -1086,3 +1087,103 @@ def commits_touching( 1 for entry in payload if isinstance(entry, dict) and (entry.get("sha") or entry.get("id")) != base ) + + +# Commit graphs kept to count the commits between a tag and a pin. A +# treeless bare clone holds commits and tags only: the files a profile reads +# come from fetch_file, by sha. +GIT_DIR = "_git" + + +def clone_dir(cache_dir: str, repo: Repo) -> Path: + """Where the commit graph of a repository is kept.""" + return Path(cache_dir) / GIT_DIR / repo.host / repo.owner / f"{repo.name}.git" + + +def _git(args: list[str], cwd: Path | None = None) -> subprocess.CompletedProcess: + env = dict(os.environ, GIT_TERMINAL_PROMPT="0") + return subprocess.run( + ["git", *args], cwd=cwd, capture_output=True, text=True, env=env, check=False + ) + + +def _has_commit(clone: Path, sha: str) -> bool: + return _git(["cat-file", "-e", f"{sha}^{{commit}}"], clone).returncode == 0 + + +def _graph(repo: Repo, sha: str, cache_dir: str, offline: bool) -> Path: + """A clone holding sha and every tag, fetched again once tags may have moved.""" + clone = clone_dir(cache_dir, repo) + url = f"https://{repo.host}/{repo.slug}.git" + if not (clone / "HEAD").is_file(): + if offline: + raise NotCachedError(f"{repo.slug}: no commit graph in the offline cache") + clone.parent.mkdir(parents=True, exist_ok=True) + result = _git(["clone", "--quiet", "--bare", "--filter=tree:0", url, str(clone)]) + if result.returncode: + raise UpstreamError(f"{url}: clone failed: {result.stderr.strip()}") + _git(["fetch", "--quiet", "--filter=tree:0", "--tags", "origin"], clone) + stamp = clone / "FETCH_HEAD" + fresh = stamp.is_file() and time.time() - stamp.stat().st_mtime <= MOVING_TTL + if offline or (fresh and _has_commit(clone, sha)): + if not _has_commit(clone, sha): + raise NotCachedError(f"{repo.slug}@{sha[:8]}: not in the offline commit graph") + return clone + # Tags are fetched again: a tag pushed since the clone can be nearer. + result = _git( + ["fetch", "--quiet", "--filter=tree:0", "--force", "--tags", "origin", + "+refs/heads/*:refs/heads/*"], clone, + ) + if result.returncode: + raise UpstreamError(f"{url}: fetch failed: {result.stderr.strip()}") + if not _has_commit(clone, sha): + # A commit no branch reaches any more: a rewritten fork, a PR head. + _git(["fetch", "--quiet", "--filter=tree:0", "origin", sha], clone) + if not _has_commit(clone, sha): + raise UpstreamError(f"{url}: {sha[:8]} is on no branch the forge serves") + return clone + + +def describe( + repo: Repo, sha: str, cache_dir: str, offline: bool = False, + match: str | None = None, +) -> tuple[str, int] | None: + """The tag nearest to sha in its history, and the commits after it. + + git describe counts the commits sha has that the tag lacks, the count a + forge compare reports as ahead. ``match`` is a glob the tag must fit. + None when no tag is reachable from sha. + """ + clone = _graph(repo, sha, cache_dir, offline) + argv = ["describe", "--tags", "--long", "--abbrev=40"] + if match: + argv += ["--match", match] + result = _git([*argv, sha], clone) + if result.returncode: + if any(text in result.stderr for text in ( + "No names found", "No tags can describe", "cannot describe", + )): + return None + raise UpstreamError(f"{repo.slug}: describe {sha[:8]}: {result.stderr.strip()}") + tag, _distance, _commit = result.stdout.strip().rsplit("-", 2) + # describe's own count is an estimate across merges (ares: 149 where the + # pin holds 143 commits the tag lacks): the exact count is rev-list's. + counted = _git(["rev-list", "--count", f"refs/tags/{tag}..{sha}"], clone) + if counted.returncode: + raise UpstreamError(f"{repo.slug}: {tag}..{sha[:8]}: {counted.stderr.strip()}") + return tag, int(counted.stdout.strip()) + + +def graph_ancestry( + repo: Repo, base: str, head: str, cache_dir: str, offline: bool = False +) -> tuple[int, int]: + """(ahead, behind) counted in the commit graph, for a pair a forge + refuses to compare (GitHub answers 422 past a diff size).""" + clone = _graph(repo, head, cache_dir, offline) + counts = [] + for spec in (f"{base}..{head}", f"{head}..{base}"): + result = _git(["rev-list", "--count", spec], clone) + if result.returncode: + raise UpstreamError(f"{repo.slug}: {spec}: {result.stderr.strip()}") + counts.append(int(result.stdout.strip())) + return counts[0], counts[1] diff --git a/scripts/version_basis.py b/scripts/version_basis.py new file mode 100644 index 000000000..c4e169d2a --- /dev/null +++ b/scripts/version_basis.py @@ -0,0 +1,280 @@ +"""Read a profile's core_version from the source its version_basis records. + +A profile states the version of the code it was read at. Copied from a +libretro .info or left behind by a pin advance, it named another release: +snes9x said 1.61 at a pin whose snes9x.h states 1.63, and four bulk advances +moved 295 pins without touching one version. version_basis records where the +version is read, so a tool can read it again at any pin: + +- ``file``: a pattern in one file of a declared repository at its pin, the + version the program states (a macro, a build file, a package file). +- ``tag``: the nearest tag in the pin's history and the commits after it, + for code that takes its version from git at build time. core_version is + the tag at distance 0, else ``<tag>-<distance>-g<pin7>``, git describe's + form. +- ``alias``: the same binary as another profile, whose version it carries. +- ``package``: an artefact read outside any source tree (an Android package, + a closed binary, a release archive): a version no pin can be asked for. + A pattern reads it from the artefact's name when the name states it. +- ``none``: the code at the pin states no version and no tag reaches it. + core_version is then null. +- ``unverified``: no reading could be made (``why``: no pin, a host the + tools cannot read, a forge gone, no build named as read, no source). + core_version stays as written and is reported unconfirmed. + +A profile whose builds live in different repositories keys version_basis by +build mode, the way it keys core_version. +""" + +from __future__ import annotations + +import re +from dataclasses import dataclass + +import upstream + +KINDS = ("file", "tag", "alias", "package", "none", "unverified") +# Values copied from a .info or a branch name, which name no version. +PLACEHOLDERS = frozenset({"git", "svn", "unknown", "master", "main", "latest", "dev", "head"}) +# Pin field of each repository field a basis may name. A mirror carries the +# source's history, so source_commit pins it too. +PIN_FIELDS = {"source": "source_commit", "source_mirror": "source_commit", + "upstream": "upstream_commit"} + +MATCH = "MATCH" +DRIFT = "DRIFT" +UNREADABLE = "UNREADABLE" +NO_BASIS = "NO_BASIS" +UNCHECKED = "UNCHECKED" +FAILING = (DRIFT, UNREADABLE, NO_BASIS) + +_FIELD = re.compile(r"\{(\d+)(?::([^}]*))?\}") + + +class VersionUnreadable(Exception): + """The basis yields no version at the pin it is asked about.""" + + +@dataclass(frozen=True) +class Reading: + mode: str + kind: str + declared: str | None + read: str | None + where: str + status: str + # What a write sets beside core_version: the tag and distance of a tag basis. + updates: tuple[tuple[str, object], ...] = () + + +def bases(profile: dict) -> dict[str, dict]: + """The basis of each build mode, "" when one covers every build.""" + basis = profile.get("version_basis") + if not isinstance(basis, dict): + return {} + if "kind" in basis: + return {"": basis} + return {str(mode): value for mode, value in basis.items() if isinstance(value, dict)} + + +def declared(profile: dict, mode: str) -> str | None: + """core_version for a build mode, as written.""" + value = profile.get("core_version") + if isinstance(value, dict): + value = value.get(mode) + return None if value is None else str(value) + + +def _by_mode(profile: dict, field: str, mode: str) -> str | None: + value = profile.get(field) + if isinstance(value, dict): + value = value.get(mode) + return str(value) if value else None + + +def is_placeholder(value: object) -> bool: + """A VCS or branch word standing for a version, alone or annotated + ("SVN (2015 snapshot)"). The schema refuses the same strings.""" + if not isinstance(value, str): + return False + return re.split(r"[\s(]", value.strip(), maxsplit=1)[0].casefold() in PLACEHOLDERS + + +def format_version(match: re.Match, template: str | None) -> str: + """The groups of a match laid out by template, `{1}.{2}` or `{4:02d}`. + + A format spec applies to the group read as an integer: FBNeo writes its + alpha number on two digits (VER_ALPHA 3 is 1.0.0.03). + """ + if not template: + return match.group(1).strip() + + def field(found: re.Match) -> str: + text = match.group(int(found.group(1))) or "" + spec = found.group(2) + return format(int(text, 0), spec) if spec else text.strip() + + return _FIELD.sub(field, template) + + +def read_text_version(text: str, pattern: str, template: str | None) -> tuple[str, int] | None: + """The version a pattern reads in a file's text, and its line number.""" + found = re.search(pattern, text, re.MULTILINE) + if not found: + return None + return format_version(found, template), text.count("\n", 0, found.start()) + 1 + + +def describe_form(tag: str, distance: int, pin: str) -> str: + """core_version of a tag basis: the tag, or git describe's long form.""" + return tag if distance == 0 else f"{tag}-{distance}-g{pin[:7]}" + + +def _repo_and_pin( + profile: dict, basis: dict, mode: str, cache_dir: str, offline: bool, +) -> tuple[upstream.Repo, str]: + """The repository a basis reads and the commit it is read at.""" + if basis.get("url"): + repo = upstream.parse_repo(str(basis["url"])) + pin = str(basis.get("commit") or "") + where = str(basis["url"]) + else: + field = str(basis.get("repo") or "source") + url = _by_mode(profile, field, mode) or "" + repo = upstream.parse_repo(url) + pin = _by_mode(profile, PIN_FIELDS.get(field, ""), mode) or "" + where = url or field + if repo is not None and not pin and field == "upstream" and profile.get("profiled_date"): + # The pin of a second repository falls back on profiled_date, + # as profile_sync resolves it. + pin = upstream.resolve_commit_at( + repo, str(profile["profiled_date"]), cache_dir, offline) or "" + if repo is None: + raise VersionUnreadable(f"{where}: not a forge repository") + if not pin: + raise VersionUnreadable(f"{repo.slug}: no pinned commit") + return repo, pin + + +def _ancestry( + repo: upstream.Repo, base: str, head: str, cache_dir: str, offline: bool, +) -> tuple[int, int] | None: + """The forge's compare, else the commit graph: GitHub refuses with 422 + a compare whose diff is too large (aps3e's tag and pin).""" + try: + relation = upstream.ancestry(repo, base, head, cache_dir, offline) + except upstream.RateLimitError: + raise + except upstream.UpstreamError: + relation = None + if relation is None: + try: + relation = upstream.graph_ancestry(repo, base, head, cache_dir, offline) + except upstream.NotCachedError: + return None + return relation + + +def read( + profile: dict, mode: str, basis: dict, cache_dir: str, offline: bool, + profiles: dict | None = None, recompute: bool = False, +) -> Reading: + """The version the basis yields at the profile's pin, against core_version. + + ``recompute`` asks git for the nearest tag again, the way a pin advance + has to: a recorded tag only proves its own distance, and a tag released + between the two pins would go unseen. + """ + stated = declared(profile, mode) + kind = str(basis.get("kind") or "") + + def reading(value: str | None, where: str, updates: tuple = ()) -> Reading: + status = MATCH if value == stated else DRIFT + return Reading(mode, kind, stated, value, where, status, updates) + + def unreadable(reason: str) -> Reading: + return Reading(mode, kind, stated, None, reason, UNREADABLE) + + try: + if kind == "none": + if recompute: + # A release tagged since the basis was written gives the + # code a version: the advance has to name it. + repo, pin = _repo_and_pin(profile, basis, mode, cache_dir, offline) + described = upstream.describe(repo, pin, cache_dir, offline) + if described is not None: + return Reading(mode, kind, stated, describe_form(*described, pin), + f"{repo.slug}: tag {described[0]} is now in " + f"{pin[:7]}'s history", DRIFT) + return reading(None, "the code states no version") + if kind == "unverified": + return Reading(mode, kind, stated, None, f"not verified: {basis.get('why')}", + UNCHECKED) + if kind == "package": + artifact = str(basis.get("artifact") or "") + if basis.get("pattern"): + # An artefact named after its version says it in its name: + # advancemame-0.94.0.tar.gz. + found = read_text_version(artifact, str(basis["pattern"]), basis.get("format")) + if found is None: + return unreadable(f"{artifact}: pattern not found") + return reading(found[0], f"named by {artifact}") + return Reading(mode, kind, stated, None, f"read from {artifact}", UNCHECKED) + if kind == "alias": + other = (profiles or {}).get(str(basis.get("of") or "")) + if other is None: + return unreadable(f"alias of {basis.get('of')}: no such profile") + return reading(declared(other, mode) if isinstance(other.get("core_version"), dict) + else declared(other, ""), f"alias of {basis['of']}") + repo, pin = _repo_and_pin(profile, basis, mode, cache_dir, offline) + if kind == "file": + path = str(basis.get("path") or "") + lines = upstream.fetch_file(repo, pin, path, cache_dir, offline) + if lines is None: + return unreadable(f"{repo.slug}@{pin[:7]}:{path}: absent") + found = read_text_version("\n".join(lines), str(basis.get("pattern") or ""), + basis.get("format")) + if found is None: + return unreadable(f"{repo.slug}@{pin[:7]}:{path}: pattern not found") + value, line = found + return reading(value, f"{repo.slug}@{pin[:7]}:{path}:{line}") + if kind == "tag": + if recompute: + described = upstream.describe(repo, pin, cache_dir, offline, basis.get("match")) + if described is None: + return unreadable(f"{repo.slug}@{pin[:7]}: no tag in its history") + tag, distance = described + else: + tag, distance = str(basis.get("tag") or ""), basis.get("distance") + commit = upstream.tag_commit(repo, tag, cache_dir, offline) + if commit is None: + return unreadable(f"{repo.slug}: no tag {tag}") + relation = (0, 0) if commit == pin else _ancestry( + repo, commit, pin, cache_dir, offline) + if relation is None: + return unreadable(f"{repo.slug}: {tag}...{pin[:7]} not comparable") + if relation[1]: + return unreadable(f"{repo.slug}: tag {tag} is not in {pin[:7]}'s history") + if relation[0] != distance: + return Reading(mode, kind, stated, describe_form(tag, relation[0], pin), + f"{repo.slug}: {pin[:7]} is {relation[0]} commits after " + f"{tag}, the basis says {distance}", DRIFT, + (("distance", relation[0]),)) + return reading(describe_form(tag, distance, pin), + f"{repo.slug}: tag {tag} + {distance}", + (("tag", tag), ("distance", distance))) + except (upstream.UpstreamError, VersionUnreadable) as exc: + return unreadable(str(exc)) + return unreadable(f"unknown kind {kind!r}") + + +def check( + profile: dict, cache_dir: str, offline: bool, profiles: dict | None = None, + recompute: bool = False, +) -> list[Reading]: + """One reading per build mode, or a NO_BASIS reading.""" + found = bases(profile) + if not found: + return [Reading("", "", declared(profile, ""), None, "no version_basis", NO_BASIS)] + return [read(profile, mode, basis, cache_dir, offline, profiles, recompute) + for mode, basis in found.items()] diff --git a/tests/fixtures/version_basis.json b/tests/fixtures/version_basis.json new file mode 100644 index 000000000..51c47f76f --- /dev/null +++ b/tests/fixtures/version_basis.json @@ -0,0 +1,94 @@ +{ + "api": { + "https://api.github.com/repos/libretro/dolphin/compare/f84df02055ab9610feec48e65648cac5a3c098fa...3aac3f052f733f8df2f1616843a4d2e14002ed11": { + "ahead_by": 437, + "behind_by": 0, + "status": "ahead" + }, + "https://api.github.com/repos/libretro/dolphin/git/ref/tags/2609": { + "object": { + "sha": "b134d026ab4e71df13b3657ea6787d499962664b", + "type": "tag" + } + }, + "https://api.github.com/repos/libretro/dolphin/git/tags/b134d026ab4e71df13b3657ea6787d499962664b": { + "object": { + "sha": "f84df02055ab9610feec48e65648cac5a3c098fa", + "type": "commit" + } + } + }, + "files": { + "github.com/libretro/FBNeo/32958a89abd645ed20387c8d31d21ede3bc48161/src/burn/version.h": "// Version number, written as vV.V.BB or vV.V.BBaa\n// (0xVVBBaa, in BCD notation)\n\n#define VER_MAJOR 1\n#define VER_MINOR 0\n#define VER_BETA 0\n#define VER_ALPHA 3\n\n#define BURN_VERSION (VER_MAJOR * 0x100000) + (VER_MINOR * 0x010000) + (((VER_BETA / 10) * 0x001000) + ((VER_BETA % 10) * 0x000100)) + (((VER_ALPHA / 10) * 0x000010) + (VER_ALPHA % 10))\n\n\n\n\n", + "github.com/libretro/snes9x/fae2fea08f74180759ef540ee94259213f503480/snes9x.h": "/*****************************************************************************\\\n Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.\n This file is licensed under the Snes9x License.\n For further information, consult the LICENSE file in the root directory.\n\\*****************************************************************************/\n\n#ifndef _SNES9X_H_\n#define _SNES9X_H_\n\n#ifndef VERSION\n#define VERSION\t\"1.63\"\n#endif\n\n#include \"port.h\"\n#include \"65c816.h\"\n#include \"messages.h\"\n\n/* All core file I/O goes through the libretro VFS via the\n file_stream_transforms wrappers (RFILE). The frontend supplies the\n VFS interface when available (see retro_set_environment);\n filestream falls back to its local implementation otherwise.\n Compressed (.gz) stream support from the old ZLIB build is gone --\n under libretro the frontend handles compressed content itself. */\n#include <streams/file_stream_transforms.h>\n#define FSTREAM\t\t\t\t\tRFILE *\n#define READ_FSTREAM(p, l, s)\trfread(p, 1, l, s)\n#define WRITE_FSTREAM(p, l, s)\trfwrite(p, 1, l, s)\n#define GETS_FSTREAM(p, l, s)\trfgets(p, l, s)\n#define GETC_FSTREAM(s)\t\t\trfgetc(s)\n#define OPEN_FSTREAM(f, m)\t\trfopen(f, m)\n#define FIND_FSTREAM(s)\t\t\trftell(s)\n#define REVERT_FSTREAM(s, o, p)\trfseek(s, o, p)\n#define CLOSE_FSTREAM(s)\t\t\trfclose(s)\n\n\n#define SNES_WIDTH\t\t\t\t\t256\n#define SNES_HEIGHT\t\t\t\t\t224\n#define SNES_HEIGHT_EXTENDED\t\t239\n#define MAX_SNES_WIDTH\t\t\t\t(SNES_WIDTH * 2)\n#define MAX_SNES_HEIGHT\t\t\t\t(SNES_HEIGHT_EXTENDED * 2)\n\n#define\tNTSC_MASTER_CLOCK\t\t\t21477272.727272 // 21477272 + 8/11 exact\n#define\tPAL_MASTER_CLOCK\t\t\t21281370.0\n#define NTSC_PROGRESSIVE_FRAME_RATE\t60.09881389744051\n#define NTSC_INTERLACED_FRAME_RATE\t59.94005994\n#define PAL_PROGRESSIVE_FRAME_RATE\t50.006977968\n\n\n#define SNES_MAX_NTSC_VCOUNTER\t\t262\n#define SNES_MAX_PAL_VCOUNTER\t\t312\n#define SNES_HCOUNTER_MAX\t\t\t341\n\n#ifndef ALLOW_CPU_OVERCLOCK\n#define ONE_CYCLE\t\t\t\t\t6\n#define SLOW_ONE_CYCLE\t\t\t\t8\n#define TWO_CYCLES\t\t\t\t\t12\n#else\n#define ONE_CYCLE (Settings.OneClockCycle)\n#define SLOW_ONE_CYCLE (Settings.OneSlowClockCycle)\n#define TWO_CYCLES (Settings.TwoClockCycles)\n#endif\n#define\tONE_DOT_CYCLE\t\t\t\t4\n\n#define SNES_CYCLES_PER_SCANLINE\t(SNES_HCOUNTER_MAX * ONE_DOT_CYCLE)\n#define SNES_SCANLINE_TIME\t\t\t(SNES_CYCLES_PER_SCANLINE / NTSC_MASTER_CLOCK)\n\n#define SNES_WRAM_REFRESH_HC_v1\t\t530\n#define SNES_WRAM_REFRESH_HC_v2\t\t538\n#define SNES_WRAM_REFRESH_CYCLES\t40\n\n#define SNES_HBLANK_START_HC\t\t1096\t\t\t\t\t// H=274\n#define\tSNES_HDMA_START_HC\t\t\t1106\t\t\t\t\t// FIXME: not true\n#define\tSNES_HBLANK_END_HC\t\t\t4\t\t\t\t\t\t// H=1\n#define\tSNES_HDMA_INIT_HC\t\t\t20\t\t\t\t\t\t// FIXME: not true\n#define\tSNES_RENDER_START_HC\t\t(128 * ONE_DOT_CYCLE)\t// FIXME: Snes9x renders a line at a time.\n\n#define SNES_TR_MASK\t\t(1 << 4)\n#define SNES_TL_MASK\t\t(1 << 5)\n#define SNES_X_MASK\t\t\t(1 << 6)\n#define SNES_A_MASK\t\t\t(1 << 7)\n#define SNES_RIGHT_MASK\t\t(1 << 8)\n#define SNES_LEFT_MASK\t\t(1 << 9)\n#define SNES_DOWN_MASK\t\t(1 << 10)\n#define SNES_UP_MASK\t\t(1 << 11)\n#define SNES_START_MASK\t\t(1 << 12)\n#define SNES_SELECT_MASK\t(1 << 13)\n#define SNES_Y_MASK\t\t\t(1 << 14)\n#define SNES_B_MASK\t\t\t(1 << 15)\n\n#define DEBUG_MODE_FLAG\t\t(1 << 0)\t// debugger\n#define TRACE_FLAG\t\t\t(1 << 1)\t// debugger\n#define SINGLE_STEP_FLAG\t(1 << 2)\t// debugger\n#define BREAK_FLAG\t\t\t(1 << 3)\t// debugger\n#define SCAN_KEYS_FLAG\t\t(1 << 4)\t// CPU\n#define HALTED_FLAG\t\t\t(1 << 12)\t// APU\n#define FRAME_ADVANCE_FLAG\t(1 << 9)\n\n#define ROM_NAME_LEN\t23\n#define AUTO_FRAMERATE\t200\n\nstruct SCPUState\n{\n\tuint32\tFlags;\n\tint32\tCycles;\n\tint32\tPrevCycles;\n\tint32\tV_Counter;\n\tuint8\t*PCBase;\n\tbool8\tNMIPending;\n\tbool8\tIRQLine;\n\tbool8\tIRQTransition;\n\tbool8\tIRQLastState;\n\tbool8\tIRQExternal;\n\tint32\tIRQPending;\n\tint32\tMemSpeed;\n\tint32\tMemSpeedx2;\n\tint32\tFastROMSpeed;\n\tbool8\tInDMA;\n\tbool8\tInHDMA;\n\tbool8\tInDMAorHDMA;\n\tbool8\tInWRAMDMAorHDMA;\n\tuint8\tHDMARanInDMA;\n\tint32\tCurrentDMAorHDMAChannel;\n\tuint8\tWhichEvent;\n\tint32\tNextEvent;\n\tbool8\tWaitingForInterrupt;\n\tuint32\tAutoSaveTimer;\n\tbool8\tSRAMModified;\n};\n\nenum\n{\n\tHC_HBLANK_START_EVENT = 1,\n\tHC_HDMA_START_EVENT = 2,\n\tHC_HCOUNTER_MAX_EVENT = 3,\n\tHC_HDMA_INIT_EVENT = 4,\n\tHC_RENDER_EVENT = 5,\n\tHC_WRAM_REFRESH_EVENT = 6\n};\n\nenum\n{\n\tIRQ_NONE = 0x0,\n\tIRQ_SET_FLAG = 0x1,\n\tIRQ_CLEAR_FLAG = 0x2,\n\tIRQ_TRIGGER_NMI = 0x4\n};\n\nstruct STimings\n{\n\tint32\tH_Max_Master;\n\tint32\tH_Max;\n\tint32\tV_Max_Master;\n\tint32\tV_Max;\n\tint32\tHBlankStart;\n\tint32\tHBlankEnd;\n\tint32\tHDMAInit;\n\tint32\tHDMAStart;\n\tint32\tNMITriggerPos;\n\tint32\tNextIRQTimer;\n\tint32\tIRQTriggerCycles;\n\tint32\tWRAMRefreshPos;\n\tint32\tRenderPos;\n\tbool8\tInterlaceField;\n\tint32\tDMACPUSync;\t\t// The cycles to synchronize DMA and CPU. Snes9x cannot emulate correctly.\n\tint32\tNMIDMADelay;\t// The delay of NMI trigger after DMA transfers. Snes9x cannot emulate correctly.\n\tint32\tIRQFlagChanging;\t// This value is just a hack.\n\tint32\tAPUSpeedup;\n\tbool8\tAPUAllowTimeOverflow;\n};\n\nstruct SSettings\n{\n\tbool8\tTraceDMA;\n\tbool8\tTraceHDMA;\n\tbool8\tTraceVRAM;\n\tbool8\tTraceUnknownRegisters;\n\tbool8\tTraceDSP;\n\tbool8\tTraceHCEvent;\n\tbool8\tTraceSMP;\n\n\tbool8\tSuperFX;\n\tuint8\tDSP;\n\tbool8\tSA1;\n\tbool8\tC4;\n\tbool8\tSDD1;\n\tbool8\tSPC7110;\n\tbool8\tSPC7110RTC;\n\tbool8\tOBC1;\n\tuint8\tSETA;\n\tbool8\tSRTC;\n\tbool8\tBS;\n\tbool8\tBSXItself;\n\tbool8\tBSXBootup;\n\tbool8\tMSU1;\n\tbool8\tMouseMaster;\n\tbool8\tSuperScopeMaster;\n\tbool8\tJustifierMaster;\n\tbool8\tMultiPlayer5Master;\n\tbool8\tMacsRifleMaster;\n\n\tbool8\tForceLoROM;\n\tbool8\tForceHiROM;\n\tbool8\tForceHeader;\n\tbool8\tForceNoHeader;\n\tbool8\tForceInterleaved;\n\tbool8\tForceInterleaved2;\n\tbool8\tForceInterleaveGD24;\n\tbool8\tForceNotInterleaved;\n\tbool8\tForcePAL;\n\tbool8\tForceNTSC;\n\tbool8\tPAL;\n\tuint32\tFrameTimePAL;\n\tuint32\tFrameTimeNTSC;\n\tuint32\tFrameTime;\n\n\tbool8\tStereo;\n\tbool8\tReverseStereo;\n\tbool8\tMute;\n\t/* The frontend has stated it will never need this frame's audio and that\n\t the state left behind will be discarded or restored. The DSP declines to\n\t run at all while this is set - see SPC_DSP::run. Distinct from Mute,\n\t which only says the output is not wanted. */\n\tbool8\tHardDisableAudio;\n\tint32\tInterpolationMethod;\n\n\tbool8\tTransparency;\n\tint32\tMode7Hires;\t\t\t\t// 0 off, 2 = 2x, 4 = 4x Mode 7 hires\n\tint32\tMode7HiresVertical;\t\t// 2x vertical resample post-pass\n\tint32\tMode7HiresBilinear;\t\t// 0 nearest, 1 stable, 2 smooth\n\tuint8\tBG_Forced;\n\tuint16 ForcedBackdrop;\n\n\tuint32\tInitialInfoStringTimeout;\n\tuint16\tDisplayColor;\n\tbool8\tBilinearFilter;\n\tbool\tShowOverscan;\n\n\tbool8\tMulti;\n\tchar\tCartAName[PATH_MAX + 1];\n\tchar\tCartBName[PATH_MAX + 1];\n\n\tbool8\tDisableGameSpecificHacks;\n\tbool8\tBlockInvalidVRAMAccessMaster;\n\tbool8\tBlockInvalidVRAMAccess;\n\tint32\tHDMATimingHack;\n\n\tuint32\tSkipFrames;\n\tuint32\tTurboSkipFrames;\n\tuint32\tAutoMaxSkipFrames;\n\tbool8\tTurboMode;\n\tuint32\tHighSpeedSeek;\n\n\tbool8\tDumpStreams;\n\tint\t\tDumpStreamsMaxFrames;\n\n\tchar InitialSnapshotFilename[PATH_MAX + 1];\n\tbool8\tFastSavestates;\n\n\tbool8\tApplyCheats;\n\tbool8\tNoPatch;\n\tbool8\tIgnorePatchChecksum;\n\tbool8\tIsPatched;\n\tint32\tAutoSaveDelay;\n\tbool8\tDontSaveOopsSnapshot;\n\tbool8\tUpAndDown;\n\n bool8 SeparateEchoBuffer;\n\tuint32\tSuperFXClockMultiplier;\n int OverclockMode;\n\tint\tOneClockCycle;\n\tint\tOneSlowClockCycle;\n\tint\tTwoClockCycles;\n\tint\tMaxSpriteTilesPerLine;\n\tint\tChannelsVolumePercent[9];\n};\n\nstruct SSNESGameFixes\n{\n\tuint8\tSRAMInitialValue;\n\tuint8\tUniracers;\n};\n\nvoid S9xMessage(int, int, const char *);\n\nextern struct SSettings\t\t\tSettings;\nextern struct SCPUState\t\t\tCPU;\nextern struct STimings\t\t\tTimings;\nextern struct SSNESGameFixes\tSNESGameFixes;\nextern char\t\t\t\t\t\tString[513];\n\n#endif\n" + }, + "profiles": { + "anarch": { + "core_version": null, + "emulator": "Anarch", + "type": "libretro", + "version_basis": { + "kind": "none" + } + }, + "beetle_psx": { + "core_version": "v0.9.44.1", + "emulator": "Beetle PSX", + "type": "libretro", + "version_basis": { + "artifact": "mednafen_psx_libretro v0.9.44.1.zip", + "kind": "package", + "pattern": "libretro (v[0-9.]+)\\.zip" + } + }, + "dolphin": { + "core_version": "2609-437-g3aac3f0", + "emulator": "Dolphin", + "source": "https://github.com/libretro/dolphin", + "source_commit": "3aac3f052f733f8df2f1616843a4d2e14002ed11", + "type": "standalone + libretro", + "upstream": "https://github.com/dolphin-emu/dolphin", + "version_basis": { + "distance": 437, + "kind": "tag", + "tag": "2609" + } + }, + "fbneo": { + "core_version": "v1.0.0.03", + "emulator": "FinalBurn Neo", + "source": "https://github.com/libretro/FBNeo", + "source_commit": "32958a89abd645ed20387c8d31d21ede3bc48161", + "type": "libretro", + "version_basis": { + "format": "v{1}.{2}.{3}.{4:02d}", + "kind": "file", + "path": "src/burn/version.h", + "pattern": "VER_MAJOR\\s+(\\d+)\\s+#define\\s+VER_MINOR\\s+(\\d+)\\s+#define\\s+VER_BETA\\s+(\\d+)\\s+#define\\s+VER_ALPHA\\s+(\\d+)" + } + }, + "mednafen_psx": { + "alias_of": "beetle_psx", + "core_version": "v0.9.44.1", + "emulator": "Beetle PSX", + "type": "alias", + "version_basis": { + "kind": "alias", + "of": "beetle_psx" + } + }, + "snes9x": { + "core_version": "1.63", + "emulator": "Snes9x", + "source": "https://github.com/libretro/snes9x", + "source_commit": "fae2fea08f74180759ef540ee94259213f503480", + "type": "libretro", + "upstream": "https://github.com/snes9xgit/snes9x", + "version_basis": { + "kind": "file", + "path": "snes9x.h", + "pattern": "#define\\s+VERSION\\s+\"([^\"]+)\"" + } + } + } +} diff --git a/tests/test_audit_regressions.py b/tests/test_audit_regressions.py index 21e351c09..7e068a04d 100644 --- a/tests/test_audit_regressions.py +++ b/tests/test_audit_regressions.py @@ -790,16 +790,6 @@ class FaqRegressions(unittest.TestCase): existence platform. Readers act on all three. """ - _MAME_GENERATIONS = { - "MAME 2000": "mame2000", - "MAME 2003": "mame2003", - "MAME 2009": "mame2009", - "MAME 2010": "mame2010", - "MAME 2015": "mame2015", - "MAME 2016": "mame2016", - "current MAME": "mame", - } - @staticmethod def _faq() -> str: # The questions about hashes and checks moved to the technical FAQ. @@ -813,17 +803,23 @@ class FaqRegressions(unittest.TestCase): with (ROOT / "emulators" / f"{key}.yml").open(encoding="utf-8") as handle: return yaml.safe_load(handle) - def test_mame_versions_match_their_profiles(self): - # The list is wrapped, so a label and its version can straddle a line. - faq = " ".join(self._faq().split()) - for label, key in self._MAME_GENERATIONS.items(): - match = re.search(rf"{re.escape(label)} \(([^)]+)\)", faq) - self.assertIsNotNone(match, f"FAQ no longer states a version for {label}") - self.assertEqual( - match.group(1), - self._profile(key)["core_version"], - f"FAQ version for {label} has drifted from emulators/{key}.yml", - ) + def test_the_romset_table_is_written_from_the_profiles(self): + # Typed by hand, the table and the prose under it kept MAME 0.160 + # and FinalBurn Neo 1.0.0.2, versions no source at the pins states, + # and the test holding them to the profiles kept the errors in step. + sys.path.insert(0, str(ROOT / "scripts")) + import generate_site # noqa: PLC0415 + from common import load_emulator_profiles # noqa: PLC0415 + + profiles = load_emulator_profiles(str(ROOT / "emulators"), skip_aliases=False) + page = (ROOT / "wiki" / "technical-faq.md").read_text(encoding="utf-8") + self.assertEqual( + page, generate_site.with_romset_table(page, profiles), + "wiki/technical-faq.md romset table is stale: run scripts/generate_site.py", + ) + prose = page.split("### How this is known", 1)[1].split("\n## ", 1)[0] + self.assertIsNone(re.search(r"\(0\.\d", prose), + "the prose under the table types a version again") def test_adler32_is_attributed_to_the_files_that_carry_it(self): dolphin = self._profile("dolphin") diff --git a/tests/test_e2e.py b/tests/test_e2e.py index 04a467896..2e0b4ed4c 100644 --- a/tests/test_e2e.py +++ b/tests/test_e2e.py @@ -4951,7 +4951,8 @@ struct BurnDriver BurnDrvneogeo = { rom = next(f for f in result["files"] if f["name"] == "sp-s2.sp1") self.assertEqual(rom["crc32"], "newcrc") self.assertEqual(rom["system"], "snk-neogeo-mvs") - self.assertEqual(result["core_version"], "v1.0.0.03") + # The version is the pin's, read through version_basis. + self.assertEqual(result["core_version"], "v1.0.0.02") def _load_config(self, platform_name: str) -> dict: diff --git a/tests/test_hash_merge.py b/tests/test_hash_merge.py index 3b28b37ce..079dfe4e5 100644 --- a/tests/test_hash_merge.py +++ b/tests/test_hash_merge.py @@ -592,7 +592,10 @@ class TestFbneoMerge(unittest.TestCase): self.assertEqual(len(archive_files), 1) self.assertNotIn("_upstream_removed", archive_files[0]) - def test_merge_updates_core_version(self) -> None: + def test_merge_leaves_core_version_to_the_pin(self) -> None: + # The hashes are read at finalburnneo/FBNeo's tip, which the + # profile's libretro/FBNeo pin does not name: the version stays the + # one version_basis reads at that pin. with tempfile.TemporaryDirectory() as td: p = Path(td) profile_path = _write_yaml(p / "fbneo.yml", _make_fbneo_profile()) @@ -600,7 +603,7 @@ class TestFbneoMerge(unittest.TestCase): result = merge_fbneo_profile(profile_path, hashes_path) - self.assertEqual(result["core_version"], "v1.0.0.03") + self.assertEqual(result["core_version"], "v1.0.0.02") class TestDiff(unittest.TestCase): @@ -849,7 +852,7 @@ class WritersPutTheValuesOnDisk(unittest.TestCase): merge_fbneo_profile(str(profile), hashes, write=True, add_new=False) written = yaml.safe_load(profile.read_text(encoding="utf-8")) entry = written["files"][0] - self.assertEqual(written["core_version"], "v1.0.0.03") + self.assertEqual(written["core_version"], "v1.0.0.02") self.assertEqual(entry["crc32"], "9036d879") self.assertEqual(entry["note"], "MVS Asia/Europe ver. 5") self.assertEqual(entry["source_ref"], "src/burn/drv/neogeo/d_neogeo.cpp:1625") diff --git a/tests/test_install_tui.py b/tests/test_install_tui.py index 158805065..b53c1bf31 100644 --- a/tests/test_install_tui.py +++ b/tests/test_install_tui.py @@ -144,7 +144,9 @@ class KeyDecoding(unittest.TestCase): for sequence in ("\x1b[25~", "\x1b[1;5A", "\x1b[M !!", "\x1b[<0;10;5M", "\x1b[?1;2c", "\x1bOZ"): with self.subTest(sequence=sequence): - self.assertEqual(self.feed(sequence + "x"), keys("char:x")) + # A mouse report is a report (MouseReports), never typed. + self.assertEqual([key for key in self.feed(sequence + "x") + if key.name != "mouse"], keys("char:x")) def test_an_incomplete_sequence_is_dropped_at_the_timeout(self): self.assertEqual(self.feed("\x1b[1"), []) @@ -1935,6 +1937,9 @@ class WorkFolders(unittest.TestCase): def draw(self, lines, cols) -> None: pass + def set_mouse(self, on: bool) -> None: + pass + def keys(self, timeout): WorkFolders.Terminal.state_to(self) return [Key("enter")] @@ -3891,6 +3896,9 @@ class Crash(unittest.TestCase): def draw(self, lines, cols) -> None: pass + def set_mouse(self, on: bool) -> None: + pass + def keys(self, timeout): raise RuntimeError("a defect") @@ -5311,6 +5319,12 @@ class TheTerminalComesBack(unittest.TestCase): raw = term.raw[since:] self.assertGreater(raw.rfind(b"\x1b[?1049l"), raw.rfind(b"\x1b[?1049h"), raw[-200:]) self.assertGreater(raw.rfind(b"\x1b[?25h"), raw.rfind(b"\x1b[?25l"), raw[-200:]) + # Clicks are given back too: a shell left with them on reads each + # one as a line of escape bytes. + for mode in (b"1000", b"1006"): + self.assertGreater(raw.rfind(b"\x1b[?" + mode + b"l"), + raw.rfind(b"\x1b[?" + mode + b"h"), raw[-200:]) + self.assertNotIn(b"\x1b[?1003h", raw) def assertModesBack(self, modes: list) -> None: fresh = self.fresh_modes() @@ -5323,6 +5337,10 @@ class TheTerminalComesBack(unittest.TestCase): self.repo() term = self.start() term.wait("Where do you play?") + # Every way out below starts with the clicks asked for, written + # right after the frame. + term.settle() + self.assertIn(install._MOUSE_ON.encode(), term.raw) how(term) return term @@ -5395,6 +5413,9 @@ class TheTerminalComesBack(unittest.TestCase): self.assertIn(b"\x1b[?1049h", term.raw[mark:]) term.wait("Where do you play?") self.assertFalse(termios.tcgetattr(term.fd)[3] & termios.ECHO) + # The clicks come back with the screen. + term.settle() + self.assertIn(install._MOUSE_ON.encode(), term.raw[mark:]) term.send("q") term.wait("PROMPT$") self.typed(term, "exit") @@ -9723,5 +9744,496 @@ class TheAndroidResultReadsWhole(unittest.TestCase): self.assertNotIn("Needed to start an emulator", said) +MOUSE_SIZES = ((40, 12), (80, 24), (120, 40)) + + +def sgr(col: int, row: int, button: int = 0, release: bool = False) -> str: + """An SGR mouse report, the cell counted from 1.""" + return f"\x1b[<{button};{col};{row}{'m' if release else 'M'}" + + +def x10(col: int, row: int, button: int = 0) -> str: + """A legacy report: 32 plus each value.""" + return "\x1b[M" + "".join(chr(32 + value) for value in (button, col, row)) + + +def drawn(state: install.TuiState, cols: int, rows: int) -> list: + """The frame as the loop draws it, its targets kept as the loop keeps them.""" + state.cols, state.rows = cols, rows + lines = install.tui_view(state, cols, rows) + state.hits = install.tui_hits(state, lines) + return lines + + +def tap(state: install.TuiState, col: int, row: int, button: int = 0) -> list: + """Press and release on one cell, columns and lines counted from 0.""" + effects = install.tui_update(state, install.TuiMouse(button, col + 1, row + 1)) + return effects + install.tui_update(state, install.TuiMouse(button, col + 1, row + 1, + True)) + + +class MouseReports(unittest.TestCase): + """Mouse reports come out of the decoder as reports, never as keys.""" + + def feed(self, *chunks: str) -> list: + decoder = install.KeyDecoder() + found = [] + for chunk in chunks: + found += decoder.feed(chunk) + return found + decoder.flush() + + def test_sgr_press_release_and_wheel(self): + Mouse = install.TuiMouse + self.assertEqual(self.feed(sgr(10, 5), sgr(10, 5, release=True)), + [Mouse(0, 10, 5), Mouse(0, 10, 5, True)]) + self.assertEqual(self.feed(sgr(3, 4, 64), sgr(3, 4, 65)), + [Mouse(64, 3, 4), Mouse(65, 3, 4)]) + self.assertEqual(self.feed(sgr(1, 1, 2)), [Mouse(2, 1, 1)]) + + def test_sgr_past_the_legacy_limit(self): + self.assertEqual(self.feed(sgr(300, 250)), [install.TuiMouse(0, 300, 250)]) + + def test_sgr_split_across_reads(self): + report = sgr(12, 7) + for cut in range(1, len(report)): + with self.subTest(cut=cut): + decoder = install.KeyDecoder() + found = decoder.feed(report[:cut]) + found += decoder.feed(report[cut:] + "j") + self.assertEqual(found, [install.TuiMouse(0, 12, 7), Key("char", "j")]) + + def test_legacy_reports(self): + Mouse = install.TuiMouse + self.assertEqual(self.feed(x10(5, 6), x10(5, 6, 3), x10(5, 6, 64)), + [Mouse(0, 5, 6), Mouse(3, 5, 6, True), Mouse(64, 5, 6)]) + + def test_legacy_bytes_are_never_keys(self): + """A position past 95 is a byte UTF-8 replaces: the report is + dropped, and none of its bytes is read as a key press.""" + for tail in ("�!!", "!�!", " qj"): + with self.subTest(tail=tail): + found = self.feed("\x1b[M" + tail, "k") + self.assertEqual([key for key in found if key.name != "mouse"], + [Key("char", "k")]) + + def test_a_cut_report_is_dropped_whole(self): + self.assertEqual(self.feed("\x1b[<0;10"), []) + self.assertEqual(self.feed("\x1b[<0;10;1;7M", "j"), [Key("char", "j")]) + + +class MouseEnabled(unittest.TestCase): + """Clicks are asked for only where they can come and are wanted.""" + + class Tty(io.StringIO): + def isatty(self) -> bool: + return True + + def blocker(self, env: dict, interactive: bool = True) -> str: + stream = self.Tty() if interactive else io.StringIO() + return install.tui_mouse_blocker(stream, stream, env) + + def test_an_xterm_like_terminal_takes_clicks(self): + for term in ("xterm", "xterm-256color", "screen-256color", "tmux-256color", + "alacritty", "foot", "xterm-kitty", "rxvt-unicode-256color"): + with self.subTest(term=term): + self.assertEqual(self.blocker({"TERM": term}), "") + + def test_what_keeps_them_off(self): + for env, interactive in ( + ({"TERM": "linux"}, True), ({"TERM": "dumb"}, True), ({}, True), + ({"TERM": "vt100"}, True), ({"TERM": "xterm"}, False), + ({"TERM": "xterm", install.TUI_PAD_ENV: "gptokeyb"}, True), + ({"TERM": "xterm", install.TUI_MOUSE_ENV: "1"}, True)): + with self.subTest(env=env, interactive=interactive): + self.assertNotEqual(self.blocker(env, interactive), "") + self.assertEqual(self.blocker({"TERM": "xterm", install.TUI_MOUSE_ENV: "0"}), "") + + def test_a_windows_console_reads_no_clicks(self): + with mock.patch.object(install.os, "name", "nt"): + self.assertIn("Windows", self.blocker({"TERM": "xterm"})) + + def test_the_terminal_writes_a_change_only(self): + terminal = install._TuiTerminal.__new__(install._TuiTerminal) + written = [] + terminal.write = written.append + terminal.mouse_allowed, terminal.mouse, terminal.entered = True, False, True + terminal.set_mouse(True) + terminal.set_mouse(True) + terminal.set_mouse(False) + self.assertEqual(written, [install._MOUSE_ON, install._MOUSE_OFF]) + terminal.mouse_allowed = False + terminal.set_mouse(True) + self.assertEqual(len(written), 2) + + def test_modes_asked_for(self): + self.assertEqual(install._MOUSE_ON, "\x1b[?1000h\x1b[?1006h") + self.assertIn(install._MOUSE_OFF, install._SCREEN_OFF) + source = (REPO_ROOT / "install.py").read_text(encoding="utf-8") + for mode in ("1002h", "1003h", "1005h", "1015h"): + self.assertNotIn("?" + mode, source) + + def test_the_text_to_copy_keeps_the_terminal_selection(self): + states = golden_states() + for name in ("result", "command", "path"): + with self.subTest(screen=name): + state = states[name] + self.assertFalse(install.tui_wants_mouse(state, drawn(state, 80, 24))) + for name in ("setup", "platforms", "plan", "systems", "options", "error", "quit"): + with self.subTest(screen=name): + state = states[name] + self.assertTrue(install.tui_wants_mouse(state, drawn(state, 80, 24))) + + def test_a_plan_naming_a_command_keeps_the_selection(self): + state = checked_state({"free": 50 * 1024 ** 3, "writable": False, + "cores": ["pcsx_rearmed"]}) + with mock.patch.object(install, "_on_read_only_mount", return_value=False): + lines = drawn(state, 120, 40) + self.assertIn("install.py", " ".join(lines)) + self.assertFalse(install.tui_wants_mouse(state, lines)) + + def test_the_view_adds_no_text(self): + """A frame drawn with its targets is the frame drawn without them.""" + patcher = mock.patch.object(install, "_mounted_cards", return_value=[]) + patcher.start() + self.addCleanup(patcher.stop) + for name, state in golden_states().items(): + for cols, rows in MOUSE_SIZES: + with self.subTest(screen=name, size=f"{cols}x{rows}"): + path = GOLDEN / f"{name}-{cols}x{rows}.txt" + if not path.exists(): + continue + lines = drawn(state, cols, rows) + text = "\n".join(line.rstrip() for line in lines) + "\n" + self.assertEqual(text, path.read_text(encoding="utf-8")) + + +class MouseOnEveryScreen(unittest.TestCase): + """A tap does on each screen what its key does, at each size.""" + + def setUp(self): + patcher = mock.patch.object(install, "_mounted_cards", return_value=[]) + patcher.start() + self.addCleanup(patcher.stop) + + @staticmethod + def twin(state: install.TuiState) -> install.TuiState: + import copy # noqa: PLC0415 + + return copy.deepcopy(state) + + def test_rows_and_bar_buttons(self): + checked = 0 + for name, base in golden_states().items(): + for cols, rows in MOUSE_SIZES: + lines = drawn(base, cols, rows) + hits = base.hits + for line, first, end, target in hits.targets: + with self.subTest(screen=name, size=f"{cols}x{rows}", target=target): + state, keyed = self.twin(base), self.twin(base) + if target[0] == "row": + index = target[1] + row_list = install.tui_rows(state) + focus = max(0, min(state.focus.get(state.screen, 0), + len(row_list) - 1)) + self.assertEqual(lines[line].style == "focus", index == focus) + # The whole width, the text's end or not. + effects = tap(state, cols - 1, line) + if index == focus: + self.assertEqual(effects, + install.tui_update(keyed, Key("enter"))) + self.assertEqual(state.stack, keyed.stack) + else: + self.assertEqual(effects, []) + self.assertEqual(state.focus[state.screen], index) + self.assertEqual(state.stack, base.stack) + elif target[0] == "key": + label = str(lines[line])[first:end].split(" ", 1)[0] + self.assertIn(label, install._BAR_CLICKS) + effects = tap(state, first, line) + self.assertEqual(effects, install.tui_update(keyed, target[1])) + self.assertEqual((state.stack, state.help), + (keyed.stack, keyed.help)) + checked += 1 + self.assertGreater(checked, 200) + + def test_two_taps_activate_a_row(self): + state = fresh_state() + lines = drawn(state, 80, 24) + another = next(index for index, line in enumerate(lines) + if "Choose another" in line or "another" in line.lower()) + self.assertEqual(tap(state, 30, another), []) + self.assertEqual(state.screen, "setup") + drawn(state, 80, 24) + tap(state, 30, another) + self.assertEqual(state.screen, "platforms") + + def test_release_acts_not_press(self): + state = fresh_state() + lines = drawn(state, 80, 24) + row = next(i for i, line in enumerate(lines) if line.style != "focus" + and getattr(line, "mark", None) and line.mark[0] == "row") + install.tui_update(state, install.TuiMouse(0, 5, row + 1)) + self.assertEqual(state.focus.get("setup", 0), 0) + # Released on another row: a swipe, which does nothing. + focused = next(i for i, line in enumerate(lines) if line.style == "focus") + install.tui_update(state, install.TuiMouse(0, 5, focused + 1, True)) + self.assertEqual(state.focus.get("setup", 0), 0) + self.assertIsNone(state.pressed) + # A release with no press before it does nothing either. + install.tui_update(state, install.TuiMouse(0, 5, row + 1, True)) + self.assertEqual(state.focus.get("setup", 0), 0) + + def test_legacy_release_names_no_button(self): + state = fresh_state() + lines = drawn(state, 80, 24) + row = next(i for i, line in enumerate(lines) if line.style != "focus" + and getattr(line, "mark", None) and line.mark[0] == "row") + decoder = install.KeyDecoder() + for event in decoder.feed(x10(5, row + 1) + x10(5, row + 1, 3)): + install.tui_update(state, event) + self.assertEqual(state.focus["setup"], lines[row].mark[1]) + + def test_right_middle_and_modified_clicks_do_nothing(self): + for button in (1, 2, 4, 8, 16, 32): + with self.subTest(button=button): + state = fresh_state() + lines = drawn(state, 80, 24) + row = next(i for i, line in enumerate(lines) if line.style != "focus" + and getattr(line, "mark", None) and line.mark[0] == "row") + self.assertEqual(tap(state, 5, row, button), []) + self.assertEqual(state.focus.get("setup", 0), 0) + + def test_a_click_on_another_frame_does_nothing(self): + """Read against the frame on screen when it came: Enter, typed in + the same read, opened the next screen before the click was read.""" + state = fresh_state() + lines = drawn(state, 80, 24) + row = next(i for i, line in enumerate(lines) if line.style != "focus" + and getattr(line, "mark", None) and line.mark[0] == "row") + install.tui_update(state, Key("char", "?")) + self.assertEqual(tap(state, 5, row), []) + self.assertTrue(state.help) + state = fresh_state() + drawn(state, 80, 24) + state.stack.append("platforms") + self.assertEqual(tap(state, 5, row), []) + self.assertEqual(state.focus.get("platforms", 0), 0) + # The same screen with its rows changed under the frame. + state = fresh_state() + drawn(state, 80, 24) + state.setups = state.setups[1:] + tap(state, 5, row) + self.assertEqual(state.focus.get("setup", 0), 0) + # A frame of another size. + state = fresh_state() + drawn(state, 80, 24) + state.cols = 100 + self.assertEqual(tap(state, 5, row), []) + self.assertEqual(state.focus.get("setup", 0), 0) + + def test_a_tap_closes_the_help(self): + state = golden_states()["help"] + drawn(state, 80, 24) + tap(state, 3, 5) + self.assertFalse(state.help) + + def long_list(self, cols: int = 40, rows: int = 12) -> install.TuiState: + state = fresh_state() + state.stack = ["setup", "platforms"] + drawn(state, cols, rows) + self.assertIsNotNone(state.hits.listing) + return state + + def test_the_wheel_scrolls_a_list_and_keeps_the_focus_in_view(self): + for cols, rows in MOUSE_SIZES[:2]: + with self.subTest(size=f"{cols}x{rows}"): + state = self.long_list(cols, rows) + first, shown, total = state.hits.listing + self.assertEqual(state.focus.get("platforms", 0), 0) + install.tui_update(state, install.TuiMouse(65, 5, 4)) + lines = drawn(state, cols, rows) + newfirst, _shown, _total = state.hits.listing + self.assertEqual(newfirst, first + install.TUI_WHEEL_LINES) + # Out of view, the focus came to the first row in view. + self.assertEqual(state.focus["platforms"], newfirst) + focused = [line.mark[1] for line in lines if line.style == "focus"] + self.assertEqual(focused, [newfirst]) + # Down again: the row in focus is still in view, and stays. + state.focus["platforms"] = newfirst + shown - 1 + drawn(state, cols, rows) + install.tui_update(state, install.TuiMouse(64, 5, 4)) + drawn(state, cols, rows) + self.assertEqual(state.hits.listing[0], first) + self.assertEqual(state.focus["platforms"], first + shown - 1) + # To the end and no further. + for _notch in range(total): + install.tui_update(state, install.TuiMouse(65, 5, 4)) + drawn(state, cols, rows) + self.assertEqual(state.hits.listing[0], total - shown) + # A key afterwards moves the focus from where the wheel put it. + at = state.focus["platforms"] + install.tui_update(state, Key("down")) + self.assertEqual(state.focus["platforms"], at + 1) + + def test_the_wheel_scrolls_a_text(self): + state = golden_states()["preview"] + state.dry_files = [{**FILES[0], "dest": f"file{n}.bin"} for n in range(40)] + drawn(state, 40, 12) + self.assertEqual(state.hits.scroll, "pager") + install.tui_update(state, install.TuiMouse(65, 5, 4)) + self.assertEqual(state.focus["preview"], install.TUI_WHEEL_LINES) + install.tui_update(state, install.TuiMouse(64, 5, 4)) + self.assertEqual(state.focus["preview"], 0) + install.tui_update(state, install.TuiMouse(64, 5, 4)) + self.assertEqual(state.focus["preview"], 0) + + def test_the_wheel_scrolls_a_long_message(self): + state = golden_states()["error"] + state.error = [f"Line {n} of a long message." for n in range(30)] + drawn(state, 40, 12) + self.assertEqual(state.hits.scroll, "error") + focus = state.focus.get("error", 0) + install.tui_update(state, install.TuiMouse(65, 5, 4)) + self.assertEqual(state.focus["error_text"], install.TUI_WHEEL_LINES) + self.assertEqual(state.focus.get("error", 0), focus) + + def test_a_tap_on_the_count_shows_the_next_page(self): + state = self.long_list() + lines = drawn(state, 40, 12) + where = next(i for i, line in enumerate(lines) + if getattr(line, "mark", None) and line.mark[0] == "scroll") + before = state.hits.listing[0] + tap(state, 2, where) + drawn(state, 40, 12) + self.assertGreater(state.hits.listing[0], before) + last = len(install.tui_rows(state)) - 1 + for _page in range(40): + if state.focus["platforms"] == last: + break + tap(state, 2, where) + drawn(state, 40, 12) + self.assertEqual(state.focus["platforms"], last) + # From the last page it goes back to the first. + tap(state, 2, where) + drawn(state, 40, 12) + self.assertEqual((state.focus["platforms"], state.hits.listing[0]), (0, 0)) + + def test_a_tap_on_a_row_ends_the_typing_of_a_filter(self): + state = self.long_list(80, 24) + install.tui_update(state, Key("char", "/")) + install.tui_update(state, Key("char", "r")) + lines = drawn(state, 80, 24) + row = next(i for i, line in enumerate(lines) if line.style != "focus" + and getattr(line, "mark", None) and line.mark[0] == "row" + and line.mark[2][0] == "platform") + tap(state, 5, row) + self.assertEqual(state.editing, "") + self.assertEqual(state.focus["platforms"], lines[row].mark[1]) + self.assertEqual(state.filters["platforms"], "r") + + +@unittest.skipUnless(pyte and pty and hasattr(pty, "fork"), + "screen tests need pyte (pip install pyte==0.8.2) and a pty") +class MouseOnAPty(unittest.TestCase): + """The real install.py --tui, clicked through a pseudo-terminal.""" + + repo = EndToEnd.repo + start = EndToEnd.start + + @staticmethod + def line_of(term: Pty, needle: str) -> int: + return next(index for index, line in enumerate(term.screen.display) if needle in line) + + def click(self, term: Pty, col: int, row: int) -> None: + term.send(sgr(col + 1, row + 1), sgr(col + 1, row + 1, release=True)) + + def test_taps_choose_a_row_and_press_the_bar(self): + self.repo() + term = self.start() + term.wait("Where do you play?") + term.settle() + self.assertIn(install._MOUSE_ON.encode(), term.raw) + row = self.line_of(term, "Another setup") + self.click(term, 60, row) + term.settle() + self.assertTrue(term.screen.buffer[row][3].reverse, term.text()) + self.assertIn("Where do you play?", term.text()) + self.click(term, 60, row) + term.wait("Which setup?") + # The bar's ? Help, pressed by a click. + bar = term.screen.display[-1] + self.click(term, bar.index("? Help") + 1, len(term.screen.display) - 1) + term.wait("Any key closes this help") + self.click(term, 10, 5) + term.wait("Which setup?") + # Legacy reports move the focus the same way. + row = self.line_of(term, " > ") + 2 + term.send(x10(20, row + 1), x10(20, row + 1, 3)) + term.settle() + self.assertTrue(term.screen.buffer[row][3].reverse, term.text()) + term.send("q") + self.assertEqual(term.close(), 130) + raw = term.raw + self.assertGreater(raw.rfind(b"\x1b[?1000l"), raw.rfind(b"\x1b[?1000h")) + + def test_the_result_gives_the_mouse_back(self): + self.repo() + term = self.start() + term.wait("Where do you play?") + term.send("\r") + term.wait("files to download") + self.click(term, 20, self.line_of(term, "> Install")) + term.wait("files installed.") + term.settle() + mark = term.raw.rfind(b"files installed") + self.assertGreater(term.raw.rfind(b"\x1b[?1000l"), term.raw.rfind(b"\x1b[?1000h")) + self.assertNotIn(install._MOUSE_ON.encode(), term.raw[mark:]) + term.send("\r") + self.assertEqual(term.close(), 0) + + def test_no_clicks_asked_when_turned_off(self): + for name, value in ((install.TUI_MOUSE_ENV, "1"), (install.TUI_PAD_ENV, "gptokeyb")): + with self.subTest(env=name): + self.repo() + self.env[name] = value + term = self.start() + term.wait("RetroBIOS") + term.settle() + term.send("\x03") + term.close() + self.assertNotIn(b"\x1b[?1000h", term.raw) + + def test_line_mode_asks_for_no_clicks(self): + self.repo() + term = self.start("--plain") + term.settle(quiet=1.0) + term.send("\x03") + term.close() + self.assertNotIn(b"\x1b[?1000h", term.raw) + self.assertNotIn(b"\x1b[?1006h", term.raw) + + def test_a_crash_gives_the_clicks_back(self): + """The crash path ends in _tui_cleanup, as every other way out.""" + master, slave = os.openpty() + self.addCleanup(os.close, master) + self.addCleanup(os.close, slave) + given = open(slave, encoding="utf-8", closefd=False) # noqa: SIM115 + shown = open(slave, "w", encoding="utf-8", closefd=False) # noqa: SIM115 + self.addCleanup(given.close) + self.addCleanup(shown.close) + terminal = install._TuiTerminal(given, shown) + terminal.mouse_allowed = True + terminal.enter() + terminal.set_mouse(True) + problems = install._tui_cleanup(terminal, [], {}, fresh_state()) + self.assertEqual(problems, []) + raw = b"" + while select.select([master], [], [], 0.2)[0]: + raw += os.read(master, 65536) + for mode in (b"1000", b"1006"): + self.assertGreater(raw.rfind(b"\x1b[?" + mode + b"l"), + raw.rfind(b"\x1b[?" + mode + b"h")) + + if __name__ == "__main__": unittest.main() diff --git a/tests/test_no_game_data.py b/tests/test_no_game_data.py index 48455fc88..79f2d6b73 100644 --- a/tests/test_no_game_data.py +++ b/tests/test_no_game_data.py @@ -289,7 +289,8 @@ class InstallerLeavesGameDataOut(unittest.TestCase): self.assertEqual(proc.returncode, 0, proc.stdout + proc.stderr) self.assertTrue((self.bios / "a.bin").exists()) self.assertFalse((self.bios / "game.wad").exists()) - self.assertIn("Left out as game data (--no-game-data): 2 files: game.wad, level.dat", + self.assertIn("Left out as game data (--no-game-data): 2 files, 1 of them not installable: " + "game.wad, level.dat", proc.stdout) def test_check_and_dry_run_leave_it_out(self): @@ -299,7 +300,8 @@ class InstallerLeavesGameDataOut(unittest.TestCase): with self.subTest(mode=mode): proc = self.run_installer("--no-game-data", mode) self.assertIn( - "Left out as game data (--no-game-data): 2 files: game.wad, level.dat", + "Left out as game data (--no-game-data): 2 files, 1 of them not installable: " + "game.wad, level.dat", proc.stdout, ) self.assertIn(listed, proc.stdout) diff --git a/tests/test_profile_sync.py b/tests/test_profile_sync.py index 1c78c1f94..a807a9bc6 100644 --- a/tests/test_profile_sync.py +++ b/tests/test_profile_sync.py @@ -60,9 +60,29 @@ from profile_sync import ( worst_status, ) import upstream +import version_basis from upstream import CompareResult, FileChange +def _version_read_as_written(profile, cache_dir, offline, profiles=None, recompute=False): + """bump_commit reads core_version again at the new pin. These fixtures + have no forge behind them, so the version reads as written here: + tests/test_version_basis.py holds the reading and the refusals.""" + stated = version_basis.declared(profile, "") + return [version_basis.Reading("", "file", stated, stated, "fixture", version_basis.MATCH)] + + +_VERSION_AS_WRITTEN = mock.patch.object(version_basis, "check", _version_read_as_written) + + +def setUpModule(): + _VERSION_AS_WRITTEN.start() + + +def tearDownModule(): + _VERSION_AS_WRITTEN.stop() + + class TestParseSourceRef(unittest.TestCase): def test_path_with_single_line(self): self.assertEqual( diff --git a/tests/test_site_r2_emulators.py b/tests/test_site_r2_emulators.py index 0ca86ecf2..9a5c5916e 100644 --- a/tests/test_site_r2_emulators.py +++ b/tests/test_site_r2_emulators.py @@ -86,9 +86,10 @@ class TheHeaderReadsAsWords(unittest.TestCase): self.assertNotIn('rb-badge-muted">japan</span>', self.page) def test_profile_version_names_the_pinned_build(self): - # DuckStation numbers builds v0.1-<commits since tag 0.1>: the pin, - # 4122fed9, is 12,070 commits past it. - self.assertRegex(str(_profile("duckstation")["core_version"]), r"^v0\.1-\d+$") + # DuckStation tags builds v0.1-<commits since tag 0.1>, and the + # pin sits past the last such tag: git describe's form names both. + self.assertRegex(str(_profile("duckstation")["core_version"]), + r"^v0\.1-\d+(-\d+-g[0-9a-f]{7})?$") def test_the_second_spelling_is_a_platform_name(self): # The lookup is case-sensitive and EmuELEC launches "Duckstation": diff --git a/tests/test_site_r4_emulators.py b/tests/test_site_r4_emulators.py index 75198dcbe..9ba99adb5 100644 --- a/tests/test_site_r4_emulators.py +++ b/tests/test_site_r4_emulators.py @@ -89,7 +89,7 @@ class AnAppThatReadsAnyBios(unittest.TestCase): class EveryArcadeCoreNamesItsRomset(unittest.TestCase): def test_finalburn_and_mame_2003_plus(self): - for name, romset in (("fbneo", "FinalBurn Neo v1.0.0.2"), + for name, romset in (("fbneo", f"FinalBurn Neo {_profile('fbneo')['core_version']}"), ("mame2003_plus", "MAME 0.78 (plus backports)")): page = _pages(name)[name] line = page.index(f"Its BIOS and game sets must come from the {romset} romset.") diff --git a/tests/test_version_basis.py b/tests/test_version_basis.py new file mode 100644 index 000000000..bb0f01511 --- /dev/null +++ b/tests/test_version_basis.py @@ -0,0 +1,351 @@ +"""core_version is read from the code at the pin, where version_basis says. + +Four bulk pin advances moved 295 pins and no version, and 54 profiles said +"Git" or "SVN" where the code states a release. These tests read the +recorded sources offline from a fixture of forge answers, hold every profile +to a basis, and hold a pin advance to reading the version again. +""" + +from __future__ import annotations + +import contextlib +import copy +import hashlib +import io +import json +import sys +import tempfile +import unittest +from pathlib import Path +from unittest import mock + +import yaml + +ROOT = Path(__file__).resolve().parent.parent +sys.path.insert(0, str(ROOT / "scripts")) + +import profile_sync # noqa: E402 +import upstream # noqa: E402 +import version_basis # noqa: E402 +from common import load_emulator_profiles # noqa: E402 +from profile_sync import ProfileReport, bump_commit # noqa: E402 + +FIXTURE = ROOT / "tests" / "fixtures" / "version_basis.json" + + +def _fixture_cache(directory: Path) -> dict: + """The fixture's forge answers, laid out as upstream caches them.""" + data = json.loads(FIXTURE.read_text(encoding="utf-8")) + for url, payload in data["api"].items(): + target = directory / "_api" / f"{hashlib.sha256(url.encode()).hexdigest()}.json" + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(upstream.ABSENT if payload is None else json.dumps(payload), + encoding="utf-8") + for key, text in data["files"].items(): + host, owner, name, sha, path = key.split("/", 4) + repo = upstream.make_repo(host, owner, name) + target = upstream.cache_path(str(directory), repo, sha, path) + target.parent.mkdir(parents=True, exist_ok=True) + target.write_text(upstream.ABSENT if text is None else text, encoding="utf-8") + return data["profiles"] + + +class ReadsTheRecordedSourceOffline(unittest.TestCase): + """The check needs nothing the cache does not hold.""" + + def setUp(self): + self.tmp = tempfile.TemporaryDirectory() + self.cache = Path(self.tmp.name) / "cache" + self.profiles = _fixture_cache(self.cache) + + def tearDown(self): + self.tmp.cleanup() + + def _check(self, name: str, profiles: dict | None = None) -> list: + profiles = profiles or self.profiles + return version_basis.check(profiles[name], str(self.cache), True, profiles) + + def test_every_kind_reads_its_version(self): + for name in self.profiles: + with self.subTest(profile=name): + readings = self._check(name) + self.assertEqual([r.status for r in readings], [version_basis.MATCH], + readings) + + def test_a_file_basis_names_the_line_it_read(self): + (reading,) = self._check("snes9x") + self.assertEqual(reading.read, "1.63") + self.assertTrue(reading.where.endswith("snes9x.h:11"), reading.where) + + def test_groups_are_laid_out_by_the_format(self): + (reading,) = self._check("fbneo") + self.assertEqual(reading.read, "v1.0.0.03") + + def test_a_version_the_code_does_not_state_is_drift(self): + for name, stale in (("snes9x", "1.61"), ("fbneo", "v1.0.0.2"), + ("dolphin", "2609"), ("mednafen_psx", "v0.9.44"), + ("anarch", "Git")): + with self.subTest(profile=name): + profiles = copy.deepcopy(self.profiles) + profiles[name]["core_version"] = stale + (reading,) = self._check(name, profiles) + self.assertEqual(reading.status, version_basis.DRIFT) + + def test_a_tag_distance_the_forge_contradicts_is_drift(self): + profiles = copy.deepcopy(self.profiles) + profiles["dolphin"]["version_basis"]["distance"] = 400 + (reading,) = self._check("dolphin", profiles) + self.assertEqual(reading.status, version_basis.DRIFT) + self.assertEqual(dict(reading.updates)["distance"], 437) + + def test_a_pattern_that_no_longer_matches_is_unreadable(self): + profiles = copy.deepcopy(self.profiles) + profiles["snes9x"]["version_basis"]["pattern"] = "#define\\s+NOPE\\s+(\\S+)" + (reading,) = self._check("snes9x", profiles) + self.assertEqual(reading.status, version_basis.UNREADABLE) + + def test_a_profile_without_basis_is_reported(self): + profiles = copy.deepcopy(self.profiles) + del profiles["snes9x"]["version_basis"] + (reading,) = self._check("snes9x", profiles) + self.assertEqual(reading.status, version_basis.NO_BASIS) + + def test_the_command_fails_on_drift_and_passes_clean(self): + emulators = Path(self.tmp.name) / "emulators" + emulators.mkdir() + for name, profile in self.profiles.items(): + body = dict(profile, files=[] if profile["type"] != "alias" else None) + body = {k: v for k, v in body.items() if v is not None or k == "core_version"} + (emulators / f"{name}.yml").write_text(yaml.safe_dump(body), encoding="utf-8") + argv = ["profile_sync.py", "--all", "--verify-version", "--offline", + "--emulators-dir", str(emulators), "--cache-dir", str(self.cache)] + + def run() -> int: + out, err = io.StringIO(), io.StringIO() + with mock.patch.object(sys, "argv", argv), contextlib.redirect_stdout(out), \ + contextlib.redirect_stderr(err): + try: + profile_sync.main() + except SystemExit as exc: + return int(exc.code or 0) + return 0 + + import common # noqa: PLC0415 + + common._emulator_profiles_cache.clear() + self.assertEqual(run(), 0) + stale = emulators / "snes9x.yml" + stale.write_text(stale.read_text(encoding="utf-8").replace("1.63", "1.61"), + encoding="utf-8") + common._emulator_profiles_cache.clear() + self.assertEqual(run(), 1) + + +class EveryProfileSaysWhereItsVersionIsRead(unittest.TestCase): + """What can be held without a forge is held here, for every profile.""" + + @classmethod + def setUpClass(cls): + cls.profiles = load_emulator_profiles(str(ROOT / "emulators"), skip_aliases=False) + + def test_every_profile_has_a_basis(self): + missing = sorted(name for name, p in self.profiles.items() + if not version_basis.bases(p)) + self.assertEqual(missing, [], "profiles without version_basis") + + def test_no_placeholder_is_a_version(self): + named = sorted( + name for name, p in self.profiles.items() + for mode in (version_basis.bases(p) or {"": {}}) + if version_basis.is_placeholder(version_basis.declared(p, mode)) + ) + self.assertEqual(named, []) + + def test_keyed_bases_follow_the_keyed_version(self): + for name, profile in self.profiles.items(): + found = version_basis.bases(profile) + if not found or "" in found: + continue + with self.subTest(profile=name): + self.assertIsInstance(profile.get("core_version"), dict) + self.assertEqual(set(found), set(profile["core_version"])) + + def test_none_states_no_version(self): + for name, profile in self.profiles.items(): + for mode, basis in version_basis.bases(profile).items(): + if basis.get("kind") == "none": + with self.subTest(profile=name, mode=mode): + self.assertIsNone(version_basis.declared(profile, mode)) + + def test_a_tag_version_is_the_describe_form_of_its_pin(self): + for name, profile in self.profiles.items(): + for mode, basis in version_basis.bases(profile).items(): + if basis.get("kind") != "tag" or basis.get("url"): + continue + field = version_basis.PIN_FIELDS[str(basis.get("repo") or "source")] + pin = version_basis._by_mode(profile, field, mode) + if not pin: + continue + with self.subTest(profile=name, mode=mode): + self.assertEqual( + version_basis.declared(profile, mode), + version_basis.describe_form(basis["tag"], basis["distance"], pin), + ) + + def test_an_alias_carries_the_version_of_its_profile(self): + for name, profile in self.profiles.items(): + for mode, basis in version_basis.bases(profile).items(): + if basis.get("kind") != "alias": + continue + with self.subTest(profile=name): + (reading,) = [r for r in version_basis.check( + profile, "", True, self.profiles) if r.mode == mode] + self.assertEqual(reading.status, version_basis.MATCH, reading) + + def test_a_package_named_after_its_version_states_it(self): + for name, profile in self.profiles.items(): + for mode, basis in version_basis.bases(profile).items(): + if basis.get("kind") != "package" or not basis.get("pattern"): + continue + with self.subTest(profile=name): + (reading,) = [r for r in version_basis.check(profile, "", True) + if r.mode == mode] + self.assertEqual(reading.status, version_basis.MATCH, reading) + + +SAMPLE = """emulator: Sample +type: libretro +source: "https://github.com/o/n" +profiled_date: "2026-01-01" +source_commit: "aaaaaaa" +core_version: "1.0" +version_basis: + kind: file + path: "version.h" + pattern: '#define\\s+VERSION\\s+"([^"]+)"' +files: [] +""" + + +class AnAdvanceReadsTheVersionAgain(unittest.TestCase): + """A pin never moves without its version: read again, or refused.""" + + def setUp(self): + self.tmp = tempfile.TemporaryDirectory() + self.path = Path(self.tmp.name) / "p.yml" + self.path.write_text(SAMPLE, encoding="utf-8") + self.report = ProfileReport( + name="p", repo="o/n", pin="aaaaaaa", head="bbbbbbb", entries=[], counts={}, + skipped=profile_sync.NO_SOURCE_REF, + ) + + def tearDown(self): + self.tmp.cleanup() + + def _reading(self, status: str, value: str | None): + return version_basis.Reading("", "file", "1.0", value, "o/n@bbbbbbb:version.h:3", status) + + def test_the_version_moves_with_the_pin(self): + seen = [] + + def check(profile, cache_dir, offline, profiles=None, recompute=False): + seen.append((profile["source_commit"], recompute)) + return [self._reading(version_basis.DRIFT, "2.0")] + + with mock.patch.object(version_basis, "check", check): + self.assertTrue(bump_commit(self.path, self.report)) + written = yaml.safe_load(self.path.read_text(encoding="utf-8")) + self.assertEqual(written["source_commit"], "bbbbbbb") + self.assertEqual(written["core_version"], "2.0") + # Read at the new pin, the nearest tag asked again. + self.assertEqual(seen, [("bbbbbbb", True)]) + + def test_an_unreadable_version_holds_the_pin(self): + with mock.patch.object(version_basis, "check", + return_value=[self._reading(version_basis.UNREADABLE, None)]): + self.assertFalse(bump_commit(self.path, self.report)) + self.assertEqual(self.path.read_text(encoding="utf-8"), SAMPLE) + + def test_a_profile_without_basis_is_not_advanced(self): + self.path.write_text(SAMPLE.split("version_basis:")[0] + "files: []\n", encoding="utf-8") + before = self.path.read_text(encoding="utf-8") + self.assertFalse(bump_commit(self.path, self.report)) + self.assertEqual(self.path.read_text(encoding="utf-8"), before) + + def test_a_package_version_is_advanced_by_hand(self): + reading = version_basis.Reading("", "package", "1.0", None, "read from x.apk", + version_basis.UNCHECKED) + with mock.patch.object(version_basis, "check", return_value=[reading]): + self.assertFalse(bump_commit(self.path, self.report)) + + +class TheWriterKeepsTheDocument(unittest.TestCase): + def test_keyed_versions_and_bases_round_trip(self): + text = ('emulator: X\nsource_commit: "abc"\ncore_version:\n standalone: "1"\n' + ' libretro: "2"\ndisplay_name: X\n') + basis = {"standalone": {"kind": "tag", "tag": "2407", "distance": 0}, + "libretro": {"kind": "none"}} + written = profile_sync.set_version_fields( + text, {"standalone": "2407", "libretro": None}, basis) + document = yaml.safe_load(written) + self.assertEqual(document["core_version"], {"standalone": "2407", "libretro": None}) + self.assertEqual(document["version_basis"], basis) + self.assertEqual(document["display_name"], "X") + self.assertIn('tag: "2407"', written) + + def test_a_missing_version_is_written_after_the_pins(self): + text = 'emulator: X\nsource_commit: "abc"\nfiles: []\n' + written = profile_sync.set_version_fields(text, None, {"kind": "none"}) + self.assertEqual(written.splitlines()[2:4], ["core_version: null", "version_basis:"]) + + +class TheSchemaRefusesPlaceholders(unittest.TestCase): + def setUp(self): + try: + import jsonschema # noqa: PLC0415 + except ImportError: + self.skipTest("jsonschema is not installed") + schema = json.loads((ROOT / "schemas" / "emulator.schema.json").read_text()) + self.validator = jsonschema.Draft202012Validator(schema) + + def _valid(self, **fields) -> bool: + profile = {"emulator": "X", "type": "libretro", "files": [], **fields} + return self.validator.is_valid(profile) + + def test_placeholders(self): + for value in ("Git", "GIT", "svn", "SVN (2015 snapshot)", "unknown", "master", + "latest", "dev", "main", "HEAD", ""): + with self.subTest(value=value): + self.assertFalse(self._valid(core_version=value)) + + def test_versions(self): + for value in ("1.63", "v1.0.0.03", "2609-437-g3aac3f0", "0.37b5", "r22", + "2026.4.1git", "developer-1", "Dev-4.0.0"): + with self.subTest(value=value): + self.assertTrue(self._valid(core_version=value)) + + def test_none_means_null(self): + self.assertTrue(self._valid(core_version=None, version_basis={"kind": "none"})) + self.assertFalse(self._valid(core_version="1.0", version_basis={"kind": "none"})) + + def test_each_kind_names_what_it_reads(self): + self.assertFalse(self._valid(version_basis={"kind": "file", "path": "v.h"})) + self.assertFalse(self._valid(version_basis={"kind": "tag", "tag": "v1"})) + self.assertFalse(self._valid(version_basis={"kind": "package"})) + self.assertTrue(self._valid(core_version="1", version_basis={"kind": "tag", "tag": "1", + "distance": 0})) + + +class VersionModesRefuseOtherFlags(unittest.TestCase): + def test_refused(self): + for extra in (["--bump-commit"], ["--check-version"], ["--strict"]): + argv = ["profile_sync.py", "--all", "--verify-version", *extra] + with self.subTest(flags=extra), mock.patch.object(sys, "argv", argv), \ + contextlib.redirect_stderr(io.StringIO()): + with self.assertRaises(SystemExit) as ctx: + profile_sync.main() + self.assertEqual(ctx.exception.code, 1) + + +if __name__ == "__main__": + unittest.main() diff --git a/wiki/installer.md b/wiki/installer.md index e165ef4f1..801d8e77d 100644 --- a/wiki/installer.md +++ b/wiki/installer.md @@ -238,6 +238,22 @@ started it, the one thing that can resume it: started from a terminal app's `-e`, a desktop entry or a launcher's `sh -c`, the key is ignored and the bar says why. +A mouse or a touch screen works too, beside the keys and buttons. A click or +a tap on a row moves the cursor there, and a second one on the row under the +cursor does what Enter does: one row of a terminal is far smaller than a +finger. The entries of the bottom line press their key, the line that says +which rows are in view shows the next page, and the wheel scrolls a list or a +text without moving the cursor unless it would leave the screen. Nothing +happens until the button or the finger comes up, and only where it went down. +The right and middle buttons do nothing. The installer asks the terminal for +clicks only on a terminal that reports them (`TERM` not `linux`, `dumb` or +unset), never on a handheld route (`RETROBIOS_PAD`) or with +`RETROBIOS_NO_MOUSE=1`, and gives them back on every way out, a stop with +Ctrl+Z included. On the result, the command line screen, any screen showing +a command and the screen where a path is typed, the terminal keeps the mouse, +so text is selected, copied and pasted as usual. Elsewhere, hold Shift while selecting (Option in macOS +Terminal and iTerm2). `--plain` never asks for clicks. + - `--tui` asks for the full screen, and names the reason when it cannot open (code 2). - `--plain`, `RETROBIOS_PLAIN=1` or `ACCESSIBLE=1` keep the questions line by @@ -1623,6 +1639,7 @@ RetroArch folder that holds only `scph5501.bin`, in the order written: | `RETROBIOS_PLAIN`, `ACCESSIBLE` | Set to anything but `0`: the questions come line by line, as with `--plain`, instead of the full-screen interface | | `RETROBIOS_PAD` | The buttons a handheld launcher's mapper sends to the full screen (`gptokeyb`, `gptokeyb_muxterm`, `muxterm`, `evmapy`, `miyoo`), so its hints name them. See [On a handheld](#on-a-handheld-the-retrobios-port) | | `RETROBIOS_IDLE_EXIT` | Seconds the full screen waits for a first button, counted while nothing runs. With none pressed, it closes with exit status 130, or with the code of the error or result screen it closed on | +| `RETROBIOS_NO_MOUSE` | Set to anything but `0`: the full screen never asks the terminal for clicks, and the mouse selects text everywhere as it does outside the installer | | `HTTPS_PROXY`, `NO_PROXY` | Honoured for every download through the standard library's default proxy handling: one names the proxy, the other the hosts to reach directly | ## When something goes wrong diff --git a/wiki/profiling.md b/wiki/profiling.md index aacb9123f..2bc88aab1 100644 --- a/wiki/profiling.md +++ b/wiki/profiling.md @@ -278,7 +278,11 @@ core_classification: community_fork source: https://github.com/libretro/dolphin upstream: https://github.com/dolphin-emu/dolphin profiled_date: 2026-03-25 -core_version: 5.0-21264 +core_version: "2609-437-g3aac3f0" +version_basis: + kind: tag + tag: "2609" + distance: 437 systems: - nintendo-gamecube - nintendo-wii @@ -509,7 +513,8 @@ reports the profile as uncheckable, and the CI job that runs | `source` | no | libretro core repository URL. A dict when the core ships under several repos | | `upstream` | no | original emulator repository URL | | `profiled_date` | see above | date of source analysis. Quote it, or YAML parses it as a date object | -| `core_version` | no | version analyzed | +| `core_version` | every profile (`tests/test_version_basis.py`) | the version of the code at the pin, read where `version_basis` says. null when the code states none, never `Git`, `SVN` or a branch name. A dict keyed by build mode when the builds differ | +| `version_basis` | every profile (`tests/test_version_basis.py`) | where `core_version` is read: `file` (`path`, `pattern`, optional `format`), `tag` (the nearest `tag` in the pin's history and its `distance`, `core_version` in git describe's form), `alias` (`of`), `package` (`artifact`, the APK or binary read) or `none`. `repo` names `upstream` when the version is the upstream tree's. `profile_sync --verify-version` reads it again, and a pin advance rewrites `core_version` from it | | `source_commit` | see above | commit SHA of `source` the code was read at. Anchors every `source_ref` line number | | `upstream_commit` | no | same, for `upstream` | | `source_branch` | no | branch `source` was read from when it is not the default one (a port living on a pull request branch). profile_sync follows it | diff --git a/wiki/technical-faq.md b/wiki/technical-faq.md index c03bd9393..27a018bb0 100644 --- a/wiki/technical-faq.md +++ b/wiki/technical-faq.md @@ -124,38 +124,40 @@ per catalog and the full list of catalogued dumps still missing. Your game sets and BIOS sets must come from the same version as your arcade emulator. +<!-- generated: romsets --> | Emulator, as RetroArch names it | Sets from | |---|---| | MAME 2000 | MAME 0.37b5 | | MAME 2003, MAME 2003 Midway | MAME 0.78 | -| MAME 2003-Plus | MAME 0.78, with later fixes | +| MAME 2003-Plus | MAME 0.78 (plus backports) | | MAME 2009 | MAME 0.135u4 | | MAME 2010 | MAME 0.139 | -| MAME 2014, MAME 2015 | MAME 0.160 | +| MAME 2014, MAME 2015 | MAME 0.159 | | MAME 2016 | MAME 0.174 | -| MAME/MESS | MAME 0.287 | -| MAME, MAME/Arcade | MAME 0.289 | -| FB Alpha 2012 CPS-1, FB Alpha 2012 CPS-2 | FB Alpha 0.2.97.28 | -| FB Alpha 2012, FB Alpha 2012 CPS-3, FB Alpha 2012 Neo Geo | FB Alpha 0.2.97.29 | -| FB Alpha 2019 | FB Alpha 0.2.97.44 | -| FinalBurn Neo, FinalBurn Neo (Neo-Geo), FinalBurn Neo (CPS-1 / CPS-2) | FinalBurn Neo 1.0.0.2 | +| MAME, MAME/Arcade, MAME/MESS | MAME 0.289 | +| FB Alpha 2012 CPS-1, FB Alpha 2012 CPS-2 | FB Alpha v0.2.97.28 | +| FB Alpha 2012 Neo Geo | FB Alpha v0.2.97.29 | +| FB Alpha 2012, FB Alpha 2012 CPS-3 | FB Alpha v0.2.97.30 | +| FB Alpha 2019 | FB Alpha v0.2.97.44 | +| FinalBurn Neo, FinalBurn Neo (CPS-1 / CPS-2), FinalBurn Neo (Neo-Geo) | FinalBurn Neo v1.0.0.03 | +<!-- /generated: romsets --> Each emulator's page names its version too. ### How this is known Arcade BIOS sets are coupled to the romset version, so there is one -profile per MAME core generation: MAME 2000 (0.37b5), MAME 2003 (0.78), -MAME 2003-Plus, MAME 2009 (0.135u4), MAME 2010 (0.139), MAME 2015 -(0.160), MAME 2016 (0.174), and current MAME (0.289), each read from that -version's own source tree, because the BIOS root sets differ between -versions. Derivatives and ports carry their own profiles on top of those -generations: `mamearcade`, `mamemess`, `mame2003_midway`, the three -`mame4droid` drops, `advancemame`, `groovymame` and `hbmame`. Recalbox -compiles two MAME versions of its own, 0.258 and 0.278, profiled as -`mame0258` and `mame0278`. The pack -ships the sets matching the core you run, and a generic unversioned arcade -pack cannot do that. +profile per MAME core generation (MAME 2000, 2003, 2003-Plus, 2009, 2010, +2015, 2016 and current MAME), each read from that version's own source +tree, because the BIOS root sets differ between versions. The table is +written from the profiles, and each version is the one the core's source +states at the revision its profile was read at. Derivatives and ports +carry their own profiles on top of those generations: `mamearcade`, +`mamemess`, `mame2003_midway`, the three `mame4droid` drops, +`advancemame`, `groovymame` and `hbmame`. Recalbox compiles two MAME +versions of its own, 0.258 and 0.278, profiled as `mame0258` and +`mame0278`. The pack ships the sets matching the core you run, and a +generic unversioned arcade pack cannot do that. ## Why does my verification report say UNTESTED? diff --git a/wiki/testing-guide.md b/wiki/testing-guide.md index 12559797c..191172856 100644 --- a/wiki/testing-guide.md +++ b/wiki/testing-guide.md @@ -61,7 +61,7 @@ Every module in `tests/`, by the area it guards. | Real-condition campaign | synthetic profiles, records and content folders, a fake host for load, disk, clock and commands, and whole passes against a libretro core built from C when a compiler and strace exist | `test_campaign` | | Automation runner, disk cleanup, asset sync and bit-flip repair | fake jobs, git repositories with a bare origin and session worktrees, a committed file with one bit flipped, canned CI runs in place of `gh` | `test_autorun` | | Truth and native export | synthetic + cached originals | `test_export_counts`, `test_export_native_layer`, `test_export_report`, `test_exporters`, `test_truth_data_dir_readers`, `test_truth_diff`, `test_truth_layout` | -| Scrapers, upstream and provenance | inline sources, synthetic | `test_batocera_md5_list`, `test_check_freshness`, `test_contributing_text`, `test_coverage_cache`, `test_data_dir_refs`, `test_dataclass_defaults`, `test_dedup`, `test_doc_pages`, `test_doc_surfaces`, `test_elec_scrapers`, `test_fbneo_parser`, `test_find_pinned_revision`, `test_hash_merge`, `test_launchers`, `test_launchers_emudeck`, `test_launchers_recalbox`, `test_launchers_retrobat`, `test_launchers_retrodeck`, `test_launchers_retropie`, `test_launchers_rocknix`, `test_mame_devices`, `test_mame_parser`, `test_mame_ref_audit`, `test_optional_dependencies`, `test_profile_sync`, `test_prose_style`, `test_provenance`, `test_refresh_data_dirs`, `test_refresh_failures`, `test_refresh_stale`, `test_retrodeck_scraper_errors`, `test_romset_recipes`, `test_schema_semantic_gate`, `test_scraper_contract`, `test_site_availability`, `test_site_content_data`, `test_site_copy`, `test_site_cores`, `test_site_density_cards`, `test_site_emulator_page`, `test_site_exports`, `test_site_funnel`, `test_site_images`, `test_site_picker`, `test_site_platform_hashes`, `test_site_r2_components`, `test_site_r2_css`, `test_site_r2_emulators`, `test_site_r2_entry`, `test_site_r2_gate`, `test_site_r2_nav`, `test_site_r2_p0`, `test_site_r2_reference`, `test_site_r2_systems`, `test_site_r2_wiki`, `test_site_r3_collection`, `test_site_r3_components`, `test_site_r3_css`, `test_site_r3_emulators`, `test_site_r3_entry`, `test_site_r3_nav`, `test_site_r3_p0`, `test_site_r3_reference`, `test_site_r3_systems`, `test_site_r3_wiki`, `test_site_r4_components`, `test_site_r4_css`, `test_site_r4_emulators`, `test_site_r4_entry`, `test_site_r4_merge`, `test_site_r4_p0`, `test_site_r4_reference`, `test_site_r4_search`, `test_site_r4_systems`, `test_site_r4_wiki`, `test_site_r5_components`, `test_site_r5_css`, `test_site_r5_emulators`, `test_site_r5_entry`, `test_site_r5_reference`, `test_site_r5_search`, `test_site_r5_systems`, `test_site_r5_wiki`, `test_site_render`, `test_site_system_links`, `test_site_validation`, `test_site_weight`, `test_site_write`, `test_source_ref_targets`, `test_upstream`, `test_upstream_index`, `test_validate_pr`, `test_validate_pr_flow`, `test_validate_pr_hashes`, `test_workflow_paths` | +| Scrapers, upstream and provenance | inline sources, synthetic | `test_batocera_md5_list`, `test_check_freshness`, `test_contributing_text`, `test_coverage_cache`, `test_data_dir_refs`, `test_dataclass_defaults`, `test_dedup`, `test_doc_pages`, `test_doc_surfaces`, `test_elec_scrapers`, `test_fbneo_parser`, `test_find_pinned_revision`, `test_hash_merge`, `test_launchers`, `test_launchers_emudeck`, `test_launchers_recalbox`, `test_launchers_retrobat`, `test_launchers_retrodeck`, `test_launchers_retropie`, `test_launchers_rocknix`, `test_mame_devices`, `test_mame_parser`, `test_mame_ref_audit`, `test_optional_dependencies`, `test_profile_sync`, `test_prose_style`, `test_provenance`, `test_refresh_data_dirs`, `test_refresh_failures`, `test_refresh_stale`, `test_retrodeck_scraper_errors`, `test_romset_recipes`, `test_schema_semantic_gate`, `test_scraper_contract`, `test_site_availability`, `test_site_content_data`, `test_site_copy`, `test_site_cores`, `test_site_density_cards`, `test_site_emulator_page`, `test_site_exports`, `test_site_funnel`, `test_site_images`, `test_site_picker`, `test_site_platform_hashes`, `test_site_r2_components`, `test_site_r2_css`, `test_site_r2_emulators`, `test_site_r2_entry`, `test_site_r2_gate`, `test_site_r2_nav`, `test_site_r2_p0`, `test_site_r2_reference`, `test_site_r2_systems`, `test_site_r2_wiki`, `test_site_r3_collection`, `test_site_r3_components`, `test_site_r3_css`, `test_site_r3_emulators`, `test_site_r3_entry`, `test_site_r3_nav`, `test_site_r3_p0`, `test_site_r3_reference`, `test_site_r3_systems`, `test_site_r3_wiki`, `test_site_r4_components`, `test_site_r4_css`, `test_site_r4_emulators`, `test_site_r4_entry`, `test_site_r4_merge`, `test_site_r4_p0`, `test_site_r4_reference`, `test_site_r4_search`, `test_site_r4_systems`, `test_site_r4_wiki`, `test_site_r5_components`, `test_site_r5_css`, `test_site_r5_emulators`, `test_site_r5_entry`, `test_site_r5_reference`, `test_site_r5_search`, `test_site_r5_systems`, `test_site_r5_wiki`, `test_site_render`, `test_site_system_links`, `test_site_validation`, `test_site_weight`, `test_site_write`, `test_source_ref_targets`, `test_upstream`, `test_upstream_index`, `test_validate_pr`, `test_version_basis`, `test_validate_pr_flow`, `test_validate_pr_hashes`, `test_workflow_paths` | ## Test architecture diff --git a/wiki/tools.md b/wiki/tools.md index 80f7fa019..30417bf00 100644 --- a/wiki/tools.md +++ b/wiki/tools.md @@ -585,6 +585,21 @@ match no entry. Both land in the `--json` report (`new_files`, with since the pin or an undeclared hash makes the profile stale. `--tree-diff` shows added, removed and renamed files in the directories the refs point at. +`core_version` is the version of the code at the pin, and `version_basis` +says where it is read: a pattern in one file (`file`), the nearest tag and +the commits after it (`tag`, written in git describe's form), the profile an +alias follows (`alias`), an artefact read outside any source tree +(`package`), or `none` when the code states nothing, with `core_version` +null. `--verify-version` reads it again at the pin and exits 1 on a +difference or a missing basis. `--set-version` writes what the code states. +A pin advance reads the version at the new pin in the same write and is +refused when it cannot: a package version moves by hand. + +```bash +python scripts/profile_sync.py --all --verify-version --changed-only +python scripts/profile_sync.py --emulator snes9x --set-version +``` + Branch tips, tags and releases are cached for six hours. `--fresh` asks the forges again for them, which matters right after an upstream commit or a hand-set pin: a tip cached before the pin reads as behind it. It is refused