From 25ffc5a24845f02ecbf4bba74d61a1bfe5bf1f13 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Fri, 13 Dec 2024 18:38:23 +1000 Subject: [PATCH] GameDatabase: Warn if multitap enabled on unsupported game Fear Effect sends a multitap read command, but doesn't know how to handle it. There's probably others. Also add a DisableMultitap trait for these games to force it off. --- src/core/game_database.cpp | 86 +++++++++++++++++++++++++++----------- src/core/game_database.h | 3 ++ 2 files changed, 64 insertions(+), 25 deletions(-) diff --git a/src/core/game_database.cpp b/src/core/game_database.cpp index 901af7be0..6d75e61eb 100644 --- a/src/core/game_database.cpp +++ b/src/core/game_database.cpp @@ -41,7 +41,7 @@ namespace GameDatabase { enum : u32 { GAME_DATABASE_CACHE_SIGNATURE = 0x45434C48, - GAME_DATABASE_CACHE_VERSION = 18, + GAME_DATABASE_CACHE_VERSION = 19, }; static const Entry* GetEntryForId(std::string_view code); @@ -85,6 +85,7 @@ static constexpr const std::array(Trait::MaxCou "ForceDeinterlacing", "ForceFullBoot", "DisableAutoAnalogMode", + "DisableMultitap", "DisableTrueColor", "DisableUpscaling", "DisableTextureFiltering", @@ -116,6 +117,7 @@ static constexpr const std::array(Trait::MaxCou TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Force Deinterlacing", "GameDatabase::Trait"), TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Force Full Boot", "GameDatabase::Trait"), TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Automatic Analog Mode", "GameDatabase::Trait"), + TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Multitap", "GameDatabase::Trait"), TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable True Color", "GameDatabase::Trait"), TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Upscaling", "GameDatabase::Trait"), TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Texture Filtering", "GameDatabase::Trait"), @@ -437,6 +439,30 @@ void GameDatabase::Entry::ApplySettings(Settings& settings, bool display_osd_mes messages.append_format(__VA_ARGS__); \ } while (0) + if (HasTrait(Trait::ForceInterpreter)) + { + if (display_osd_messages && settings.cpu_execution_mode != CPUExecutionMode::Interpreter) + APPEND_MESSAGE(TRANSLATE_SV("GameDatabase", "CPU recompiler disabled.")); + + settings.cpu_execution_mode = CPUExecutionMode::Interpreter; + } + + if (HasTrait(Trait::ForceFullBoot)) + { + if (display_osd_messages && settings.bios_patch_fast_boot) + APPEND_MESSAGE(TRANSLATE_SV("GameDatabase", "Fast boot disabled.")); + + settings.bios_patch_fast_boot = false; + } + + if (HasTrait(Trait::DisableMultitap)) + { + if (display_osd_messages && settings.multitap_mode != MultitapMode::Disabled) + APPEND_MESSAGE(TRANSLATE_SV("GameDatabase", "Multitap disabled.")); + + settings.multitap_mode = MultitapMode::Disabled; + } + if (display_crop_mode.has_value()) { if (display_osd_messages && settings.display_crop_mode != display_crop_mode.value()) @@ -448,14 +474,6 @@ void GameDatabase::Entry::ApplySettings(Settings& settings, bool display_osd_mes settings.display_crop_mode = display_crop_mode.value(); } - if (HasTrait(Trait::ForceInterpreter)) - { - if (display_osd_messages && settings.cpu_execution_mode != CPUExecutionMode::Interpreter) - APPEND_MESSAGE(TRANSLATE_SV("GameDatabase", "CPU recompiler disabled.")); - - settings.cpu_execution_mode = CPUExecutionMode::Interpreter; - } - if (HasTrait(Trait::ForceSoftwareRenderer)) { if (display_osd_messages && settings.gpu_renderer != GPURenderer::Software) @@ -515,14 +533,6 @@ void GameDatabase::Entry::ApplySettings(Settings& settings, bool display_osd_mes } } - if (HasTrait(Trait::ForceFullBoot)) - { - if (display_osd_messages && settings.bios_patch_fast_boot) - APPEND_MESSAGE(TRANSLATE_SV("GameDatabase", "Fast boot disabled.")); - - settings.bios_patch_fast_boot = false; - } - if (HasTrait(Trait::DisableTrueColor)) { if (display_osd_messages && settings.gpu_true_color) @@ -749,16 +759,25 @@ void GameDatabase::Entry::ApplySettings(Settings& settings, bool display_osd_mes supported_controller_string.append(Controller::GetControllerInfo(supported_ctype)->GetDisplayName()); } - Host::AddKeyedOSDMessage( - "gamedb_controller_unsupported", - fmt::format(TRANSLATE_FS("GameDatabase", - "Controller in port {0} ({1}) is not supported for {2}.\nSupported controllers: " - "{3}\nPlease configure a supported controller from the list above."), - i + 1u, Controller::GetControllerInfo(ctype)->GetDisplayName(), System::GetGameTitle(), - supported_controller_string), + Host::AddIconOSDWarning( + fmt::format("GameDBController{}Unsupported", i), ICON_EMOJI_WARNING, + fmt::format( + TRANSLATE_FS("GameDatabase", + "Controller in Port {0} ({1}) is not supported for this game.\nSupported controllers: " + "{2}\nPlease configure a supported controller from the list above."), + i + 1u, Controller::GetControllerInfo(ctype)->GetDisplayName(), supported_controller_string), Host::OSD_CRITICAL_ERROR_DURATION); } } + + if (g_settings.multitap_mode != MultitapMode::Disabled && !(supported_controllers & SUPPORTS_MULTITAP_BIT)) + { + Host::AddIconOSDMessage("GameDBMultitapUnsupported", ICON_EMOJI_WARNING, + TRANSLATE_STR("GameDatabase", + "This game does not support multitap, but multitap is enabled.\n" + " This may result in dropped controller inputs."), + Host::OSD_CRITICAL_ERROR_DURATION); + } } #undef BIT_FOR @@ -841,6 +860,9 @@ std::string GameDatabase::Entry::GenerateCompatibilityReport() const ret.append_format(" - {}\n", Controller::GetControllerInfo(static_cast(j))->GetDisplayName()); } + if (supported_controllers & SUPPORTS_MULTITAP_BIT) + ret.append(" - Multitap\n"); + ret.append("\n"); } @@ -1303,7 +1325,7 @@ bool GameDatabase::ParseYamlEntry(Entry* entry, const ryml::ConstNodeRef& value) if (const std::optional libcrypt_val = StringUtil::FromChars(to_stringview(libcrypt.val())); libcrypt_val.has_value()) { - entry->traits[static_cast(Trait::IsLibCryptProtected)] = true; + entry->traits[static_cast(Trait::IsLibCryptProtected)] = libcrypt_val.value(); } else { @@ -1311,6 +1333,20 @@ bool GameDatabase::ParseYamlEntry(Entry* entry, const ryml::ConstNodeRef& value) } } + if (const ryml::ConstNodeRef& multitap = value.find_child(to_csubstr("multitap")); multitap.valid()) + { + if (const std::optional multitap_val = StringUtil::FromChars(to_stringview(multitap.val())); + multitap_val.has_value()) + { + if (multitap_val.value()) + entry->supported_controllers |= Entry::SUPPORTS_MULTITAP_BIT; + } + else + { + WARNING_LOG("Invalid multitap value in {}", entry->serial); + } + } + if (const ryml::ConstNodeRef settings = value.find_child(to_csubstr("settings")); settings.valid() && settings.has_children()) { diff --git a/src/core/game_database.h b/src/core/game_database.h index 7ac805e86..2324c9bc0 100644 --- a/src/core/game_database.h +++ b/src/core/game_database.h @@ -41,6 +41,7 @@ enum class Trait : u32 ForceDeinterlacing, ForceFullBoot, DisableAutoAnalogMode, + DisableMultitap, DisableTrueColor, DisableUpscaling, DisableTextureFiltering, @@ -94,6 +95,8 @@ enum class Language : u8 struct Entry { + static constexpr u16 SUPPORTS_MULTITAP_BIT = (1u << static_cast(ControllerType::Count)); + std::string_view serial; std::string_view title; std::string_view genre;