From a4e1bb9537f46b8c0f7fb02986f03f3d4d113d85 Mon Sep 17 00:00:00 2001 From: collecting Date: Thu, 2 Oct 2025 23:36:20 +0000 Subject: [PATCH 1/3] fix: Properties Scaling --- .../configuration/configure_per_game.ui | 462 ++++++++++-------- 1 file changed, 255 insertions(+), 207 deletions(-) diff --git a/src/citron/configuration/configure_per_game.ui b/src/citron/configuration/configure_per_game.ui index 2e020b719..1325527b9 100644 --- a/src/citron/configuration/configure_per_game.ui +++ b/src/citron/configuration/configure_per_game.ui @@ -23,220 +23,262 @@ - + - + 0 0 - - Info + + + 320 + 0 + - - - - - - 0 - 0 - - - - - 256 - 256 - - - - - 256 - 256 - - - - Qt::ScrollBarAlwaysOff - - - Qt::ScrollBarAlwaysOff - - - false - - - - - - - - - true - - - true - - - - - - - true - - - true - - - - - - - Name - - - - - - - Title ID - - - - - - - true - - - true - - - - - - - true - - - true - - - - - - - true - - - true - - - - - - - Filename - - - - - - - true - - - true - - - - - - - true - - - true - - - - - - - Format - - - - - - - Version - - - - - - - Size - - - - - - - Developer - - - - - - - Base Build ID - - - - - - - true - - - true - - - - - - - Update Build ID - - - - - - - true - - - true - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - + + Qt::ScrollBarAlwaysOff + + + true + + + + + 0 + 0 + 318 + 538 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + Info + + + + + + + 0 + 0 + + + + + 256 + 256 + + + + + 256 + 256 + + + + Qt::ScrollBarAlwaysOff + + + Qt::ScrollBarAlwaysOff + + + false + + + + + + + + + true + + + true + + + + + + + true + + + true + + + + + + + Name + + + + + + + Title ID + + + + + + + true + + + true + + + + + + + true + + + true + + + + + + + true + + + true + + + + + + + Filename + + + + + + + true + + + true + + + + + + + true + + + true + + + + + + + Format + + + + + + + Version + + + + + + + Size + + + + + + + Developer + + + + + + + Base Build ID + + + + + + + true + + + true + + + + + + + Update Build ID + + + + + + + true + + + true + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + @@ -248,6 +290,12 @@ true + + + 0 + 0 + + -1 From cca68bc42e10dfd902fe76fb1aaa40c227c85936 Mon Sep 17 00:00:00 2001 From: collecting Date: Thu, 2 Oct 2025 23:37:01 +0000 Subject: [PATCH 2/3] fix: Properties Scaling --- .../configuration/configure_input_per_game.ui | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/citron/configuration/configure_input_per_game.ui b/src/citron/configuration/configure_input_per_game.ui index fbd8eab1c..0e7021f37 100644 --- a/src/citron/configuration/configure_input_per_game.ui +++ b/src/citron/configuration/configure_input_per_game.ui @@ -53,7 +53,7 @@ - + 0 0 @@ -88,7 +88,7 @@ - + 0 0 @@ -123,7 +123,7 @@ - + 0 0 @@ -158,7 +158,7 @@ - + 0 0 @@ -193,7 +193,7 @@ - + 0 0 @@ -228,7 +228,7 @@ - + 0 0 @@ -263,7 +263,7 @@ - + 0 0 @@ -298,7 +298,7 @@ - + 0 0 From f59aa1e0251c6dc68394686f705020cabd4ebbf4 Mon Sep 17 00:00:00 2001 From: collecting Date: Thu, 2 Oct 2025 23:37:46 +0000 Subject: [PATCH 3/3] fix: Properties Scaling --- .../configuration/configure_per_game.cpp | 523 +++++++++--------- 1 file changed, 264 insertions(+), 259 deletions(-) diff --git a/src/citron/configuration/configure_per_game.cpp b/src/citron/configuration/configure_per_game.cpp index f3d62af27..e9c549ab2 100644 --- a/src/citron/configuration/configure_per_game.cpp +++ b/src/citron/configuration/configure_per_game.cpp @@ -51,28 +51,33 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::string& file_name, std::vector& vk_device_records, Core::System& system_) - : QDialog(parent), - ui(std::make_unique()), title_id{title_id_}, system{system_}, - builder{std::make_unique(this, !system_.IsPoweredOn())}, - tab_group{std::make_shared>()} { +: QDialog(parent), +ui(std::make_unique()), title_id{title_id_}, system{system_}, +builder{std::make_unique(this, !system_.IsPoweredOn())}, +tab_group{std::make_shared>()} { const auto file_path = std::filesystem::path(Common::FS::ToU8String(file_name)); const auto config_file_name = title_id == 0 ? Common::FS::PathToUTF8String(file_path.filename()) - : fmt::format("{:016X}", title_id); + : fmt::format("{:016X}", title_id); game_config = std::make_unique(config_file_name, Config::ConfigType::PerGameConfig); addons_tab = std::make_unique(system_, this); audio_tab = std::make_unique(system_, tab_group, *builder, this); cpu_tab = std::make_unique(system_, tab_group, *builder, this); graphics_advanced_tab = - std::make_unique(system_, tab_group, *builder, this); + std::make_unique(system_, tab_group, *builder, this); graphics_tab = std::make_unique( system_, vk_device_records, [&]() { graphics_advanced_tab->ExposeComputeOption(); }, - [](Settings::AspectRatio, Settings::ResolutionSetup) {}, tab_group, *builder, this); + [](Settings::AspectRatio, Settings::ResolutionSetup) {}, tab_group, *builder, this); input_tab = std::make_unique(system_, game_config.get(), this); linux_tab = std::make_unique(system_, tab_group, *builder, this); system_tab = std::make_unique(system_, tab_group, *builder, this); ui->setupUi(this); + // THIS IS THE NEW FIX: Force a minimum height on the window. + setMinimumHeight(400); + + layout()->setSizeConstraint(QLayout::SetDefaultConstraint); + ui->tabWidget->addTab(addons_tab.get(), tr("Add-Ons")); ui->tabWidget->addTab(system_tab.get(), tr("System")); ui->tabWidget->addTab(cpu_tab.get(), tr("CPU")); @@ -83,10 +88,10 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id_, const std::st // Only show Linux tab on Unix linux_tab->setVisible(false); -#ifdef __unix__ + #ifdef __unix__ linux_tab->setVisible(true); ui->tabWidget->addTab(linux_tab.get(), tr("Linux")); -#endif + #endif setFocusPolicy(Qt::ClickFocus); setWindowTitle(tr("Properties")); @@ -115,15 +120,15 @@ void ConfigurePerGame::ApplyConfiguration() { input_tab->ApplyConfiguration(); if (Settings::IsDockedMode() && Settings::values.players.GetValue()[0].controller_type == - Settings::ControllerType::Handheld) { + Settings::ControllerType::Handheld) { Settings::values.use_docked_mode.SetValue(Settings::ConsoleMode::Handheld); - Settings::values.use_docked_mode.SetGlobal(true); - } + Settings::values.use_docked_mode.SetGlobal(true); + } - system.ApplySettings(); - Settings::LogSettings(); + system.ApplySettings(); + Settings::LogSettings(); - game_config->SaveAllValues(); + game_config->SaveAllValues(); } void ConfigurePerGame::changeEvent(QEvent* event) { @@ -159,300 +164,300 @@ void ConfigurePerGame::LoadConfiguration() { QStringLiteral("%1").arg(title_id, 16, 16, QLatin1Char{'0'}).toUpper()); const FileSys::PatchManager pm{title_id, system.GetFileSystemController(), - system.GetContentProvider()}; - const auto control = pm.GetControlMetadata(); - const auto loader = Loader::GetLoader(system, file); + system.GetContentProvider()}; + const auto control = pm.GetControlMetadata(); + const auto loader = Loader::GetLoader(system, file); - if (control.first != nullptr) { - ui->display_version->setText(QString::fromStdString(control.first->GetVersionString())); - ui->display_name->setText(QString::fromStdString(control.first->GetApplicationName())); - ui->display_developer->setText(QString::fromStdString(control.first->GetDeveloperName())); - } else { - std::string title; - if (loader->ReadTitle(title) == Loader::ResultStatus::Success) - ui->display_name->setText(QString::fromStdString(title)); + if (control.first != nullptr) { + ui->display_version->setText(QString::fromStdString(control.first->GetVersionString())); + ui->display_name->setText(QString::fromStdString(control.first->GetApplicationName())); + ui->display_developer->setText(QString::fromStdString(control.first->GetDeveloperName())); + } else { + std::string title; + if (loader->ReadTitle(title) == Loader::ResultStatus::Success) + ui->display_name->setText(QString::fromStdString(title)); - FileSys::NACP nacp; - if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success) - ui->display_developer->setText(QString::fromStdString(nacp.GetDeveloperName())); + FileSys::NACP nacp; + if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success) + ui->display_developer->setText(QString::fromStdString(nacp.GetDeveloperName())); - ui->display_version->setText(QStringLiteral("1.0.0")); - } + ui->display_version->setText(QStringLiteral("1.0.0")); + } - if (control.second != nullptr) { - scene->clear(); - - QPixmap map; - const auto bytes = control.second->ReadAllBytes(); - map.loadFromData(bytes.data(), static_cast(bytes.size())); - - scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(), - Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); - } else { - std::vector bytes; - if (loader->ReadIcon(bytes) == Loader::ResultStatus::Success) { + if (control.second != nullptr) { scene->clear(); QPixmap map; + const auto bytes = control.second->ReadAllBytes(); map.loadFromData(bytes.data(), static_cast(bytes.size())); scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); - } - } + } else { + std::vector bytes; + if (loader->ReadIcon(bytes) == Loader::ResultStatus::Success) { + scene->clear(); - ui->display_filename->setText(QString::fromStdString(file->GetName())); + QPixmap map; + map.loadFromData(bytes.data(), static_cast(bytes.size())); - ui->display_format->setText( - QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))); - - const auto valueText = ReadableByteSize(file->GetSize()); - ui->display_size->setText(valueText); - - // Display Build ID(s) if available - std::string base_build_id_hex; - std::string update_build_id_hex; - - // Try to get build ID based on file type - const auto file_type = loader->GetFileType(); - - if (file_type == Loader::FileType::NSO) { - // For NSO files, read the build ID directly from the header - if (file->GetSize() >= 0x100) { - std::array header_data{}; - if (file->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { - // Build ID is at offset 0x40 in NSO header - std::array build_id{}; - std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); - base_build_id_hex = Common::HexToString(build_id, false); + scene->addPixmap(map.scaled(ui->icon_view->width(), ui->icon_view->height(), + Qt::IgnoreAspectRatio, Qt::SmoothTransformation)); } } - } else if (file_type == Loader::FileType::DeconstructedRomDirectory) { - // For deconstructed ROM directories, read from the main NSO file - const auto main_dir = file->GetContainingDirectory(); - if (main_dir) { - const auto main_nso = main_dir->GetFile("main"); - if (main_nso && main_nso->GetSize() >= 0x100) { + + ui->display_filename->setText(QString::fromStdString(file->GetName())); + + ui->display_format->setText( + QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))); + + const auto valueText = ReadableByteSize(file->GetSize()); + ui->display_size->setText(valueText); + + // Display Build ID(s) if available + std::string base_build_id_hex; + std::string update_build_id_hex; + + // Try to get build ID based on file type + const auto file_type = loader->GetFileType(); + + if (file_type == Loader::FileType::NSO) { + // For NSO files, read the build ID directly from the header + if (file->GetSize() >= 0x100) { std::array header_data{}; - if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { + if (file->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { // Build ID is at offset 0x40 in NSO header std::array build_id{}; std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); base_build_id_hex = Common::HexToString(build_id, false); } } + } else if (file_type == Loader::FileType::DeconstructedRomDirectory) { + // For deconstructed ROM directories, read from the main NSO file + const auto main_dir = file->GetContainingDirectory(); + if (main_dir) { + const auto main_nso = main_dir->GetFile("main"); + if (main_nso && main_nso->GetSize() >= 0x100) { + std::array header_data{}; + if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { + // Build ID is at offset 0x40 in NSO header + std::array build_id{}; + std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); + base_build_id_hex = Common::HexToString(build_id, false); + } + } + } + } else { + // For other file types (XCI, NSP, NCA), try to extract build ID directly + try { + if (file_type == Loader::FileType::XCI) { + // For XCI files, try to construct with the proper parameters + try { + // First try to get the program ID from the XCI to use proper parameters + FileSys::XCI xci_temp(file); + if (xci_temp.GetStatus() == Loader::ResultStatus::Success) { + // Try to get the program NCA from the secure partition + FileSys::XCI xci(file, title_id, 0); // Use detected title_id + if (xci.GetStatus() == Loader::ResultStatus::Success) { + auto program_nca = xci.GetNCAByType(FileSys::NCAContentType::Program); + if (program_nca && program_nca->GetStatus() == Loader::ResultStatus::Success) { + auto exefs = program_nca->GetExeFS(); + if (exefs) { + auto main_nso = exefs->GetFile("main"); + if (main_nso && main_nso->GetSize() >= 0x100) { + std::array header_data{}; + if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { + std::array build_id{}; + std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); + base_build_id_hex = Common::HexToString(build_id, false); + } + } + } + } + } + } + } catch (...) { + // XCI might be encrypted or have other issues + // Fall back to checking if it's installed in the content provider + const auto& content_provider = system.GetContentProvider(); + auto base_nca = content_provider.GetEntry(title_id, FileSys::ContentRecordType::Program); + if (base_nca && base_nca->GetStatus() == Loader::ResultStatus::Success) { + auto exefs = base_nca->GetExeFS(); + if (exefs) { + auto main_nso = exefs->GetFile("main"); + if (main_nso && main_nso->GetSize() >= 0x100) { + std::array header_data{}; + if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { + std::array build_id{}; + std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); + base_build_id_hex = Common::HexToString(build_id, false); + } + } + } + } + } + } else if (file_type == Loader::FileType::NSP) { + // For NSP files, try to construct and parse directly + FileSys::NSP nsp(file); + if (nsp.GetStatus() == Loader::ResultStatus::Success) { + auto exefs = nsp.GetExeFS(); + if (exefs) { + auto main_nso = exefs->GetFile("main"); + if (main_nso && main_nso->GetSize() >= 0x100) { + std::array header_data{}; + if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { + std::array build_id{}; + std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); + base_build_id_hex = Common::HexToString(build_id, false); + } + } + } + } + } else if (file_type == Loader::FileType::NCA) { + // For NCA files, try to construct and parse directly + FileSys::NCA nca(file); + if (nca.GetStatus() == Loader::ResultStatus::Success) { + auto exefs = nca.GetExeFS(); + if (exefs) { + auto main_nso = exefs->GetFile("main"); + if (main_nso && main_nso->GetSize() >= 0x100) { + std::array header_data{}; + if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { + std::array build_id{}; + std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); + base_build_id_hex = Common::HexToString(build_id, false); + } + } + } + } + } + } catch (...) { + // If anything fails, continue without the build ID + } } - } else { - // For other file types (XCI, NSP, NCA), try to extract build ID directly + + // Try to get update build ID from patch manager and content provider try { - if (file_type == Loader::FileType::XCI) { - // For XCI files, try to construct with the proper parameters - try { - // First try to get the program ID from the XCI to use proper parameters - FileSys::XCI xci_temp(file); - if (xci_temp.GetStatus() == Loader::ResultStatus::Success) { - // Try to get the program NCA from the secure partition - FileSys::XCI xci(file, title_id, 0); // Use detected title_id - if (xci.GetStatus() == Loader::ResultStatus::Success) { - auto program_nca = xci.GetNCAByType(FileSys::NCAContentType::Program); - if (program_nca && program_nca->GetStatus() == Loader::ResultStatus::Success) { - auto exefs = program_nca->GetExeFS(); - if (exefs) { - auto main_nso = exefs->GetFile("main"); - if (main_nso && main_nso->GetSize() >= 0x100) { - std::array header_data{}; - if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { - std::array build_id{}; - std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); - base_build_id_hex = Common::HexToString(build_id, false); - } - } - } - } - } - } - } catch (...) { - // XCI might be encrypted or have other issues - // Fall back to checking if it's installed in the content provider - const auto& content_provider = system.GetContentProvider(); - auto base_nca = content_provider.GetEntry(title_id, FileSys::ContentRecordType::Program); - if (base_nca && base_nca->GetStatus() == Loader::ResultStatus::Success) { - auto exefs = base_nca->GetExeFS(); - if (exefs) { - auto main_nso = exefs->GetFile("main"); - if (main_nso && main_nso->GetSize() >= 0x100) { - std::array header_data{}; - if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { - std::array build_id{}; - std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); - base_build_id_hex = Common::HexToString(build_id, false); - } - } - } - } - } - } else if (file_type == Loader::FileType::NSP) { - // For NSP files, try to construct and parse directly - FileSys::NSP nsp(file); - if (nsp.GetStatus() == Loader::ResultStatus::Success) { - auto exefs = nsp.GetExeFS(); - if (exefs) { - auto main_nso = exefs->GetFile("main"); - if (main_nso && main_nso->GetSize() >= 0x100) { - std::array header_data{}; - if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { - std::array build_id{}; - std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); - base_build_id_hex = Common::HexToString(build_id, false); + // Method 1: Try through patch manager (more reliable for updates) + const FileSys::PatchManager pm_update{title_id, system.GetFileSystemController(), + system.GetContentProvider()}; + + // Check if patch manager has update information + const auto update_version = pm_update.GetGameVersion(); + if (update_version.has_value() && update_version.value() > 0) { + // There's an update, try to get its build ID through the patch manager + // The patch manager should have access to the update NCA + + // Try to get the update NCA through the patch manager's content provider + const auto& content_provider = system.GetContentProvider(); + const auto update_title_id = FileSys::GetUpdateTitleID(title_id); + auto update_nca = content_provider.GetEntry(update_title_id, FileSys::ContentRecordType::Program); + + if (update_nca && update_nca->GetStatus() == Loader::ResultStatus::Success) { + auto exefs = update_nca->GetExeFS(); + if (exefs) { + auto main_nso = exefs->GetFile("main"); + if (main_nso && main_nso->GetSize() >= 0x100) { + std::array header_data{}; + if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { + std::array build_id{}; + std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); + update_build_id_hex = Common::HexToString(build_id, false); + } } } } } - } else if (file_type == Loader::FileType::NCA) { - // For NCA files, try to construct and parse directly - FileSys::NCA nca(file); - if (nca.GetStatus() == Loader::ResultStatus::Success) { - auto exefs = nca.GetExeFS(); - if (exefs) { - auto main_nso = exefs->GetFile("main"); - if (main_nso && main_nso->GetSize() >= 0x100) { - std::array header_data{}; - if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { - std::array build_id{}; - std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); - base_build_id_hex = Common::HexToString(build_id, false); + + // Method 2: If patch manager approach didn't work, try direct content provider access + if (update_build_id_hex.empty()) { + const auto& content_provider = system.GetContentProvider(); + const auto update_title_id = FileSys::GetUpdateTitleID(title_id); + auto update_nca = content_provider.GetEntry(update_title_id, FileSys::ContentRecordType::Program); + + if (update_nca && update_nca->GetStatus() == Loader::ResultStatus::Success) { + auto exefs = update_nca->GetExeFS(); + if (exefs) { + auto main_nso = exefs->GetFile("main"); + if (main_nso && main_nso->GetSize() >= 0x100) { + std::array header_data{}; + if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { + std::array build_id{}; + std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); + update_build_id_hex = Common::HexToString(build_id, false); + } } } } } - } + + // Method 3: Try to use the patch manager's GetPatches to detect updates + if (update_build_id_hex.empty()) { + const auto patches = pm_update.GetPatches(); + for (const auto& patch : patches) { + if (patch.type == FileSys::PatchType::Update && patch.enabled) { + // There's an enabled update patch, but we couldn't get its build ID + // This indicates an update is available but not currently loaded + break; + } + } + } } catch (...) { - // If anything fails, continue without the build ID + // If update build ID extraction fails, continue with just base } - } - // Try to get update build ID from patch manager and content provider - try { - // Method 1: Try through patch manager (more reliable for updates) - const FileSys::PatchManager pm_update{title_id, system.GetFileSystemController(), - system.GetContentProvider()}; + // Try to get the actual running build ID from system (this will be the update if one is applied) + const auto& system_build_id = system.GetApplicationProcessBuildID(); + const auto system_build_id_hex = Common::HexToString(system_build_id, false); - // Check if patch manager has update information - const auto update_version = pm_update.GetGameVersion(); - if (update_version.has_value() && update_version.value() > 0) { - // There's an update, try to get its build ID through the patch manager - // The patch manager should have access to the update NCA - - // Try to get the update NCA through the patch manager's content provider - const auto& content_provider = system.GetContentProvider(); - const auto update_title_id = FileSys::GetUpdateTitleID(title_id); - auto update_nca = content_provider.GetEntry(update_title_id, FileSys::ContentRecordType::Program); - - if (update_nca && update_nca->GetStatus() == Loader::ResultStatus::Success) { - auto exefs = update_nca->GetExeFS(); - if (exefs) { - auto main_nso = exefs->GetFile("main"); - if (main_nso && main_nso->GetSize() >= 0x100) { - std::array header_data{}; - if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { - std::array build_id{}; - std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); - update_build_id_hex = Common::HexToString(build_id, false); - } - } - } + // If we have a system build ID and it's different from the base, it's likely the update + if (!system_build_id_hex.empty() && system_build_id_hex != std::string(64, '0')) { + if (!base_build_id_hex.empty() && system_build_id_hex != base_build_id_hex) { + // System build ID is different from base, so it's the update + update_build_id_hex = system_build_id_hex; + } else if (base_build_id_hex.empty()) { + // No base build ID found, use system as base + base_build_id_hex = system_build_id_hex; } } - // Method 2: If patch manager approach didn't work, try direct content provider access - if (update_build_id_hex.empty()) { - const auto& content_provider = system.GetContentProvider(); - const auto update_title_id = FileSys::GetUpdateTitleID(title_id); - auto update_nca = content_provider.GetEntry(update_title_id, FileSys::ContentRecordType::Program); - - if (update_nca && update_nca->GetStatus() == Loader::ResultStatus::Success) { - auto exefs = update_nca->GetExeFS(); - if (exefs) { - auto main_nso = exefs->GetFile("main"); - if (main_nso && main_nso->GetSize() >= 0x100) { - std::array header_data{}; - if (main_nso->ReadBytes(header_data.data(), 0x100, 0) == 0x100) { - std::array build_id{}; - std::memcpy(build_id.data(), header_data.data() + 0x40, 0x20); - update_build_id_hex = Common::HexToString(build_id, false); - } - } - } + // Additional check: if we still don't have an update build ID but we know there's an update + // (from the Add-Ons tab showing v1.0.1 etc), try alternative detection methods + bool update_detected = false; + if (update_build_id_hex.empty() && !base_build_id_hex.empty()) { + // Check if the patch manager indicates an update is available + const auto update_version = pm.GetGameVersion(); + if (update_version.has_value() && update_version.value() > 0) { + update_detected = true; } - } - // Method 3: Try to use the patch manager's GetPatches to detect updates - if (update_build_id_hex.empty()) { - const auto patches = pm_update.GetPatches(); + // Also check patches + const auto patches = pm.GetPatches(); for (const auto& patch : patches) { if (patch.type == FileSys::PatchType::Update && patch.enabled) { - // There's an enabled update patch, but we couldn't get its build ID - // This indicates an update is available but not currently loaded + update_detected = true; break; } } } - } catch (...) { - // If update build ID extraction fails, continue with just base - } - // Try to get the actual running build ID from system (this will be the update if one is applied) - const auto& system_build_id = system.GetApplicationProcessBuildID(); - const auto system_build_id_hex = Common::HexToString(system_build_id, false); + // Display the Build IDs in separate fields + bool has_base = !base_build_id_hex.empty() && base_build_id_hex != std::string(64, '0'); + bool has_update = !update_build_id_hex.empty() && update_build_id_hex != std::string(64, '0'); - // If we have a system build ID and it's different from the base, it's likely the update - if (!system_build_id_hex.empty() && system_build_id_hex != std::string(64, '0')) { - if (!base_build_id_hex.empty() && system_build_id_hex != base_build_id_hex) { - // System build ID is different from base, so it's the update - update_build_id_hex = system_build_id_hex; - } else if (base_build_id_hex.empty()) { - // No base build ID found, use system as base - base_build_id_hex = system_build_id_hex; - } - } - - // Additional check: if we still don't have an update build ID but we know there's an update - // (from the Add-Ons tab showing v1.0.1 etc), try alternative detection methods - bool update_detected = false; - if (update_build_id_hex.empty() && !base_build_id_hex.empty()) { - // Check if the patch manager indicates an update is available - const auto update_version = pm.GetGameVersion(); - if (update_version.has_value() && update_version.value() > 0) { - update_detected = true; + // Set Base Build ID + if (has_base) { + ui->display_build_id->setText(QString::fromStdString(base_build_id_hex)); + } else { + ui->display_build_id->setText(tr("Not Available")); } - // Also check patches - const auto patches = pm.GetPatches(); - for (const auto& patch : patches) { - if (patch.type == FileSys::PatchType::Update && patch.enabled) { - update_detected = true; - break; - } + // Set Update Build ID + if (has_update) { + ui->display_update_build_id->setText(QString::fromStdString(update_build_id_hex)); + } else if (update_detected) { + ui->display_update_build_id->setText(tr("Available (Run game to show)")); + } else { + ui->display_update_build_id->setText(tr("Not Available")); } - } - - // Display the Build IDs in separate fields - bool has_base = !base_build_id_hex.empty() && base_build_id_hex != std::string(64, '0'); - bool has_update = !update_build_id_hex.empty() && update_build_id_hex != std::string(64, '0'); - - // Set Base Build ID - if (has_base) { - ui->display_build_id->setText(QString::fromStdString(base_build_id_hex)); - } else { - ui->display_build_id->setText(tr("Not Available")); - } - - // Set Update Build ID - if (has_update) { - ui->display_update_build_id->setText(QString::fromStdString(update_build_id_hex)); - } else if (update_detected) { - ui->display_update_build_id->setText(tr("Available (Run game to show)")); - } else { - ui->display_update_build_id->setText(tr("Not Available")); - } }