From 6597483755bd09cf2c7c2a815775856d1ee957a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 23 Oct 2026 11:24:55 +0200 Subject: [PATCH] UI: No game-or-video prompt for a disc whose game is a placeholder The EUR Video Demo Disc's UMD_DATA.BIN says GVA, but its EBOOT.BIN and BOOT.BIN are all zeroes, so "Play game" could only fail. It now goes straight to the XMB, like "Watch video". What the disc reports to the emulated PSP doesn't change. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/Loaders.cpp | 26 ++++++++++++++++++++++++++ Core/Loaders.h | 3 +++ UI/MainScreen.cpp | 5 +++++ 3 files changed, 34 insertions(+) diff --git a/Core/Loaders.cpp b/Core/Loaders.cpp index 549df566bc..8dd58240b6 100644 --- a/Core/Loaders.cpp +++ b/Core/Loaders.cpp @@ -451,6 +451,32 @@ u32 DetectUmdDiscType(FileLoader *fileLoader) { return DetectUmdDiscType(&umd, ""); } +bool UmdHasBootableGame(FileLoader *fileLoader) { + std::string error; + std::shared_ptr bd(ConstructBlockDevice(fileLoader, &error)); + if (!bd) { + return false; + } + SequentialHandleAllocator handles; + ISOFileSystem umd(&handles, bd); + for (const char *path : { "/PSP_GAME/SYSDIR/EBOOT.BIN", "/PSP_GAME/SYSDIR/BOOT.BIN" }) { + if (!umd.GetFileInfo(path).exists) { + continue; + } + const int handle = umd.OpenFile(path, FILEACCESS_READ); + if (handle < 0) { + continue; + } + u8 head[4]{}; + const size_t read = umd.ReadFile(handle, head, sizeof(head)); + umd.CloseFile(handle); + if (read == sizeof(head) && (memcmp(head, "~PSP", 4) == 0 || memcmp(head, "\x7F" "ELF", 4) == 0)) { + return true; + } + } + return false; +} + // Close the return value with ZipClose (if non-null, of course). ZipContainer ZipOpenPath(const Path &fileName) { ZipContainer z(fileName); diff --git a/Core/Loaders.h b/Core/Loaders.h index 3e7eabcee7..c4311629d0 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -172,6 +172,9 @@ class IFileSystem; u32 DetectUmdDiscType(IFileSystem *fs, std::string_view root); // The same for a disc image file. 0 if it can't be opened as one. u32 DetectUmdDiscType(FileLoader *fileLoader); +// Whether the image's PSP_GAME has an actual executable. The EUR Video Demo Disc lists a game +// (UMD_DATA.BIN says GVA) whose EBOOT.BIN and BOOT.BIN are all zeroes. +bool UmdHasBootableGame(FileLoader *fileLoader); enum class ArchiveType { ZIP, diff --git a/UI/MainScreen.cpp b/UI/MainScreen.cpp index e56d95ad4c..2586ec7cb0 100644 --- a/UI/MainScreen.cpp +++ b/UI/MainScreen.cpp @@ -126,6 +126,11 @@ static void LaunchFile(ScreenManager *screenManager, Screen *currentScreen, cons if (!fileLoader || !(DetectUmdDiscType(fileLoader.get()) & PSP_UMD_TYPE_VIDEO)) { break; } + if (!UmdHasBootableGame(fileLoader.get())) { + // The game is only a placeholder, so there's just the video. + LaunchInEmuScreen(screenManager, currentScreen, new EmuScreen(vshPath, path, false)); + return; + } auto ga = GetI18NCategory(I18NCat::GAME); const std::vector choices = { std::string(ga->T("Play game")), std::string(ga->T("Watch video")) }; UI::ListPopupScreen *popup = new UI::ListPopupScreen(ga->T("This disc has both a game and video"), choices, -1, [=](int choice) {