From a641305c75d4120a005ee6d8be24496dd8aed0f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Thu, 3 Sep 2026 11:16:18 -0600 Subject: [PATCH] sceFont: use the fonts in NAND, and take them off the disc if we have none sceFont never looked at flash0:, so a firmware the user installed was ignored and we always fell back to our bundled substitutes - despite the "ignoring NAND" warning suggesting otherwise. It reads flash0:/font now, after the game's own fonts and the classic ms0 override. And if there's nothing in NAND, we unpack just flash0:/font out of the firmware updater on the running disc, which most UMDs carry. That turns "install a firmware first" into something that happens by itself for anyone playing a retail game. EmulatedModelGeneration moves from InstallUpdateScreen into PSARUnpack so both callers pick the same firmware file list. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq --- Core/HLE/sceFont.cpp | 48 ++++++++++++++++++++++++++++++++++++++ Core/Util/PSARUnpack.cpp | 5 ++++ Core/Util/PSARUnpack.h | 4 ++++ UI/InstallUpdateScreen.cpp | 7 ------ 4 files changed, 57 insertions(+), 7 deletions(-) diff --git a/Core/HLE/sceFont.cpp b/Core/HLE/sceFont.cpp index ade70d0f64..37564343b9 100644 --- a/Core/HLE/sceFont.cpp +++ b/Core/HLE/sceFont.cpp @@ -22,6 +22,10 @@ #include "Core/Core.h" #include "Core/System.h" #include "Core/Font/PGF.h" +#include "Core/Util/PathUtil.h" +#include "Core/Util/PSARUnpack.h" +#include "Common/Data/Text/I18n.h" +#include "Common/System/OSD.h" constexpr int MAX_FONT_REFS = 4; @@ -872,6 +876,44 @@ static LoadedFont *GetLoadedFont(u32 handle, bool allowClosed) { } } +// The real PSP fonts live in flash0, which we only have if the user installed a firmware. +static const char *const g_nandFontPath = "flash0:/font/"; + +// Most UMDs carry a firmware updater, so if we have no real fonts yet we can pull them out of +// whatever game is running rather than making the user find an updater themselves. Our bundled +// substitutes are a good deal worse - some homebrew even trips over them. +static bool InstallFontsFromDiscUpdater() { + if (!MountedDiscHasUpdater()) { + return false; + } + + INFO_LOG(Log::sceFont, "No fonts in NAND, trying the firmware updater on the disc (%s)", + ReadMountedDiscUpdaterVersion().c_str()); + + PSARUnpackOptions options; + options.model = EmulatedModelGeneration(); + // Just the fonts - the rest of a firmware is none of our business here. + options.prefixFilter = g_nandFontPath; + + PSARUnpackStats stats; + std::string error; + if (!UnpackUpdaterFromMountedDisc(GetSysDirectory(DIRECTORY_NAND), options, &stats, &error)) { + WARN_LOG(Log::sceFont, "Couldn't unpack fonts from the disc's updater: %s", error.c_str()); + return false; + } + if (stats.written == 0) { + // The updater has no font list for the model we're emulating. + WARN_LOG(Log::sceFont, "The disc's updater had no fonts for this PSP model"); + return false; + } + + INFO_LOG(Log::sceFont, "Installed %d font files from the disc's %s updater", stats.written, + stats.firmwareVersion.c_str()); + auto sy = GetI18NCategory(I18NCat::SYSTEM); + g_OSD.Show(OSDType::MESSAGE_SUCCESS, sy->T("Installed fonts"), stats.firmwareVersion, 3.0f); + return true; +} + static void __LoadInternalFonts() { if (internalFonts.size()) { // Fonts already loaded. @@ -883,6 +925,8 @@ static void __LoadInternalFonts() { const bool checkClassicOverrides = pspFileSystem.GetFileInfo(fontOverridePath).exists; if (checkClassicOverrides) { WARN_LOG(Log::sceFont, "Classic font overrides active, ignoring NAND: %s", fontOverridePath.c_str()); + } else if (!pspFileSystem.GetFileInfo(std::string(g_nandFontPath) + "ltn0.pgf").exists) { + InstallFontsFromDiscUpdater(); } if ((pspFileSystem.GetFileInfo("disc0:/PSP_GAME/USRDIR/zh_gb.pgf").exists) && (pspFileSystem.GetFileInfo("disc0:/PSP_GAME/USRDIR/oldfont.prx").exists)) { @@ -913,6 +957,10 @@ static void __LoadInternalFonts() { // No game font, let's try classic override path. NOTE: This is not recommended - use flash0. fontFilename = fontOverridePath + entry.fileName; bufferRead = pspFileSystem.ReadEntireFile(fontFilename, buffer, true) >= 0; + } else if (!bufferRead) { + // The real fonts, from a firmware the user installed or that we took off a disc. + fontFilename = std::string(g_nandFontPath) + entry.fileName; + bufferRead = pspFileSystem.ReadEntireFile(fontFilename, buffer, true) >= 0; } if (!bufferRead) { diff --git a/Core/Util/PSARUnpack.cpp b/Core/Util/PSARUnpack.cpp index ca3b27299d..7028cc31da 100644 --- a/Core/Util/PSARUnpack.cpp +++ b/Core/Util/PSARUnpack.cpp @@ -26,6 +26,7 @@ #include "Common/File/Path.h" #include "Common/Log.h" #include "Common/StringUtils.h" +#include "Core/Config.h" #include "Core/ELF/ParamSFO.h" #include "Core/ELF/PBPReader.h" #include "Core/ELF/PrxDecrypter.h" @@ -334,6 +335,10 @@ const char *PSPModelGenerationToString(PSPModelGeneration generation) { } } +PSPModelGeneration EmulatedModelGeneration() { + return g_Config.iPSPModel == PSP_MODEL_FAT ? PSPModelGeneration::PSP_1000 : PSPModelGeneration::PSP_2000; +} + bool PSPModelGenerationFromString(std::string_view name, PSPModelGeneration *generation) { if (equalsNoCase(name, "any")) { *generation = PSPModelGeneration::Any; diff --git a/Core/Util/PSARUnpack.h b/Core/Util/PSARUnpack.h index 620932c5d9..f3ef8a5d18 100644 --- a/Core/Util/PSARUnpack.h +++ b/Core/Util/PSARUnpack.h @@ -67,6 +67,10 @@ enum class PSPModelGeneration { }; const char *PSPModelGenerationToString(PSPModelGeneration generation); +// The model we're claiming to be. An updater carries one file list per hardware revision, and +// anything the chosen model's list doesn't name isn't part of its firmware, so unpacking this +// one keeps flash0 consistent with what the emulator reports to games. +PSPModelGeneration EmulatedModelGeneration(); // Accepts "01g".."12g", a bare number, or "any". Returns false if it's none of those. bool PSPModelGenerationFromString(std::string_view name, PSPModelGeneration *generation); diff --git a/UI/InstallUpdateScreen.cpp b/UI/InstallUpdateScreen.cpp index 5af068c453..abe8a4de2b 100644 --- a/UI/InstallUpdateScreen.cpp +++ b/UI/InstallUpdateScreen.cpp @@ -36,13 +36,6 @@ #include "UI/MiscViews.h" #include "UI/EmuScreen.h" -// An updater carries one file list per hardware revision, and anything the chosen model's list -// doesn't name isn't part of its firmware. Unpacking the model we claim to be keeps flash0 -// consistent with what the emulator reports to games. -static PSPModelGeneration EmulatedModelGeneration() { - return g_Config.iPSPModel == PSP_MODEL_FAT ? PSPModelGeneration::PSP_1000 : PSPModelGeneration::PSP_2000; -} - InstallUpdateScreen::InstallUpdateScreen(const Path &path, std::string_view title) : UISimpleBaseDialogScreen(Path(), SimpleDialogFlags::ContentsCanScroll), path_(path), title_(title) { destination_ = GetSysDirectory(DIRECTORY_NAND);