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.
This commit is contained in:
Stenzek 2024-12-13 18:38:23 +10:00
parent 50fbaf90e6
commit 25ffc5a248
No known key found for this signature in database
2 changed files with 64 additions and 25 deletions

View File

@ -41,7 +41,7 @@ namespace GameDatabase {
enum : u32 enum : u32
{ {
GAME_DATABASE_CACHE_SIGNATURE = 0x45434C48, GAME_DATABASE_CACHE_SIGNATURE = 0x45434C48,
GAME_DATABASE_CACHE_VERSION = 18, GAME_DATABASE_CACHE_VERSION = 19,
}; };
static const Entry* GetEntryForId(std::string_view code); static const Entry* GetEntryForId(std::string_view code);
@ -85,6 +85,7 @@ static constexpr const std::array<const char*, static_cast<size_t>(Trait::MaxCou
"ForceDeinterlacing", "ForceDeinterlacing",
"ForceFullBoot", "ForceFullBoot",
"DisableAutoAnalogMode", "DisableAutoAnalogMode",
"DisableMultitap",
"DisableTrueColor", "DisableTrueColor",
"DisableUpscaling", "DisableUpscaling",
"DisableTextureFiltering", "DisableTextureFiltering",
@ -116,6 +117,7 @@ static constexpr const std::array<const char*, static_cast<size_t>(Trait::MaxCou
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Force Deinterlacing", "GameDatabase::Trait"), TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Force Deinterlacing", "GameDatabase::Trait"),
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Force Full Boot", "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 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 True Color", "GameDatabase::Trait"),
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Upscaling", "GameDatabase::Trait"), TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Upscaling", "GameDatabase::Trait"),
TRANSLATE_DISAMBIG_NOOP("GameDatabase", "Disable Texture Filtering", "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__); \ messages.append_format(__VA_ARGS__); \
} while (0) } 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_crop_mode.has_value())
{ {
if (display_osd_messages && settings.display_crop_mode != display_crop_mode.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(); 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 (HasTrait(Trait::ForceSoftwareRenderer))
{ {
if (display_osd_messages && settings.gpu_renderer != GPURenderer::Software) 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 (HasTrait(Trait::DisableTrueColor))
{ {
if (display_osd_messages && settings.gpu_true_color) 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()); supported_controller_string.append(Controller::GetControllerInfo(supported_ctype)->GetDisplayName());
} }
Host::AddKeyedOSDMessage( Host::AddIconOSDWarning(
"gamedb_controller_unsupported", fmt::format("GameDBController{}Unsupported", i), ICON_EMOJI_WARNING,
fmt::format(TRANSLATE_FS("GameDatabase", fmt::format(
"Controller in port {0} ({1}) is not supported for {2}.\nSupported controllers: " TRANSLATE_FS("GameDatabase",
"{3}\nPlease configure a supported controller from the list above."), "Controller in Port {0} ({1}) is not supported for this game.\nSupported controllers: "
i + 1u, Controller::GetControllerInfo(ctype)->GetDisplayName(), System::GetGameTitle(), "{2}\nPlease configure a supported controller from the list above."),
supported_controller_string), i + 1u, Controller::GetControllerInfo(ctype)->GetDisplayName(), supported_controller_string),
Host::OSD_CRITICAL_ERROR_DURATION); 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 #undef BIT_FOR
@ -841,6 +860,9 @@ std::string GameDatabase::Entry::GenerateCompatibilityReport() const
ret.append_format(" - {}\n", Controller::GetControllerInfo(static_cast<ControllerType>(j))->GetDisplayName()); ret.append_format(" - {}\n", Controller::GetControllerInfo(static_cast<ControllerType>(j))->GetDisplayName());
} }
if (supported_controllers & SUPPORTS_MULTITAP_BIT)
ret.append(" - Multitap\n");
ret.append("\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<bool>(to_stringview(libcrypt.val())); if (const std::optional libcrypt_val = StringUtil::FromChars<bool>(to_stringview(libcrypt.val()));
libcrypt_val.has_value()) libcrypt_val.has_value())
{ {
entry->traits[static_cast<size_t>(Trait::IsLibCryptProtected)] = true; entry->traits[static_cast<size_t>(Trait::IsLibCryptProtected)] = libcrypt_val.value();
} }
else 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<bool>(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")); if (const ryml::ConstNodeRef settings = value.find_child(to_csubstr("settings"));
settings.valid() && settings.has_children()) settings.valid() && settings.has_children())
{ {

View File

@ -41,6 +41,7 @@ enum class Trait : u32
ForceDeinterlacing, ForceDeinterlacing,
ForceFullBoot, ForceFullBoot,
DisableAutoAnalogMode, DisableAutoAnalogMode,
DisableMultitap,
DisableTrueColor, DisableTrueColor,
DisableUpscaling, DisableUpscaling,
DisableTextureFiltering, DisableTextureFiltering,
@ -94,6 +95,8 @@ enum class Language : u8
struct Entry struct Entry
{ {
static constexpr u16 SUPPORTS_MULTITAP_BIT = (1u << static_cast<u8>(ControllerType::Count));
std::string_view serial; std::string_view serial;
std::string_view title; std::string_view title;
std::string_view genre; std::string_view genre;