diff --git a/pcsx2-qt/Settings/EmulationSettingsWidget.cpp b/pcsx2-qt/Settings/EmulationSettingsWidget.cpp index aca06ea4d7..34c200f403 100644 --- a/pcsx2-qt/Settings/EmulationSettingsWidget.cpp +++ b/pcsx2-qt/Settings/EmulationSettingsWidget.cpp @@ -46,6 +46,7 @@ EmulationSettingsWidget::EmulationSettingsWidget(SettingsDialog* dialog, QWidget SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.cheats, "EmuCore", "EnableCheats", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.widescreenPatches, "EmuCore", "EnableWideScreenPatches", false); + SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.noInterlacingPatches, "EmuCore", "EnableNoInterlacingPatches", false); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.perGameSettings, "EmuCore", "EnablePerGameSettings", true); SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.hostFilesystem, "EmuCore", "HostFs", false); diff --git a/pcsx2-qt/Settings/EmulationSettingsWidget.ui b/pcsx2-qt/Settings/EmulationSettingsWidget.ui index d0a7fb7a21..4541674fb1 100644 --- a/pcsx2-qt/Settings/EmulationSettingsWidget.ui +++ b/pcsx2-qt/Settings/EmulationSettingsWidget.ui @@ -125,13 +125,20 @@ Game Settings - + Enable Per-Game Settings + + + + Enable Widescreen Patches + + + @@ -139,20 +146,20 @@ - - - - Enable Widescreen Patches - - - - + Enable Host Filesystem + + + + Enable No-Interlacing Patches + + + diff --git a/pcsx2/Config.h b/pcsx2/Config.h index 786e407276..7120b3b814 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -940,6 +940,7 @@ struct Pcsx2Config EnableCheats : 1, // enables cheat detection and application EnablePINE : 1, // enables inter-process communication EnableWideScreenPatches : 1, + EnableNoInterlacingPatches : 1, // TODO - Vaser - where are these settings exposed in the Qt UI? EnableRecordingTools : 1, #ifdef PCSX2_CORE @@ -1032,6 +1033,7 @@ namespace EmuFolders extern std::string Logs; extern std::string Cheats; extern std::string CheatsWS; + extern std::string CheatsNI; extern std::string Resources; extern std::string Cache; extern std::string Covers; diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index 6dab8c6a7e..3b3d759b3a 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -44,6 +44,7 @@ namespace EmuFolders std::string Logs; std::string Cheats; std::string CheatsWS; + std::string CheatsNI; std::string Resources; std::string Cache; std::string Covers; @@ -1040,6 +1041,7 @@ void Pcsx2Config::LoadSave(SettingsWrapper& wrap) SettingsWrapBitBool(EnableCheats); SettingsWrapBitBool(EnablePINE); SettingsWrapBitBool(EnableWideScreenPatches); + SettingsWrapBitBool(EnableNoInterlacingPatches); SettingsWrapBitBool(EnableRecordingTools); #ifdef PCSX2_CORE SettingsWrapBitBool(EnableGameFixes); @@ -1189,6 +1191,7 @@ void Pcsx2Config::CopyConfig(const Pcsx2Config& cfg) EnableCheats = cfg.EnableCheats; EnablePINE = cfg.EnablePINE; EnableWideScreenPatches = cfg.EnableWideScreenPatches; + EnableNoInterlacingPatches = cfg.EnableNoInterlacingPatches; EnableRecordingTools = cfg.EnableRecordingTools; UseBOOT2Injection = cfg.UseBOOT2Injection; PatchBios = cfg.PatchBios; @@ -1216,6 +1219,7 @@ void EmuFolders::SetDefaults() Logs = Path::Combine(DataRoot, "logs"); Cheats = Path::Combine(DataRoot, "cheats"); CheatsWS = Path::Combine(DataRoot, "cheats_ws"); + CheatsNI = Path::Combine(DataRoot, "cheats_ni"); Covers = Path::Combine(DataRoot, "covers"); GameSettings = Path::Combine(DataRoot, "gamesettings"); Cache = Path::Combine(DataRoot, "cache"); @@ -1239,6 +1243,7 @@ void EmuFolders::LoadConfig(SettingsInterface& si) Logs = LoadPathFromSettings(si, DataRoot, "Logs", "logs"); Cheats = LoadPathFromSettings(si, DataRoot, "Cheats", "cheats"); CheatsWS = LoadPathFromSettings(si, DataRoot, "CheatsWS", "cheats_ws"); + CheatsNI = LoadPathFromSettings(si, DataRoot, "CheatsNI", "cheats_ni"); Covers = LoadPathFromSettings(si, DataRoot, "Covers", "covers"); GameSettings = LoadPathFromSettings(si, DataRoot, "GameSettings", "gamesettings"); Cache = LoadPathFromSettings(si, DataRoot, "Cache", "cache"); @@ -1251,6 +1256,7 @@ void EmuFolders::LoadConfig(SettingsInterface& si) Console.WriteLn("Logs Directory: %s", Logs.c_str()); Console.WriteLn("Cheats Directory: %s", Cheats.c_str()); Console.WriteLn("CheatsWS Directory: %s", CheatsWS.c_str()); + Console.WriteLn("CheatsNI Directory: %s", CheatsNI.c_str()); Console.WriteLn("Covers Directory: %s", Covers.c_str()); Console.WriteLn("Game Settings Directory: %s", GameSettings.c_str()); Console.WriteLn("Cache Directory: %s", Cache.c_str()); @@ -1267,6 +1273,7 @@ void EmuFolders::Save(SettingsInterface& si) si.SetStringValue("Folders", "Logs", Path::MakeRelative(Logs, DataRoot).c_str()); si.SetStringValue("Folders", "Cheats", Path::MakeRelative(Cheats, DataRoot).c_str()); si.SetStringValue("Folders", "CheatsWS", Path::MakeRelative(CheatsWS, DataRoot).c_str()); + si.SetStringValue("Folders", "CheatsNI", Path::MakeRelative(CheatsNI, DataRoot).c_str()); si.SetStringValue("Folders", "Cache", Path::MakeRelative(Cache, DataRoot).c_str()); si.SetStringValue("Folders", "Textures", Path::MakeRelative(Textures, DataRoot).c_str()); } @@ -1281,6 +1288,7 @@ bool EmuFolders::EnsureFoldersExist() result = FileSystem::CreateDirectoryPath(Logs.c_str(), false) && result; result = FileSystem::CreateDirectoryPath(Cheats.c_str(), false) && result; result = FileSystem::CreateDirectoryPath(CheatsWS.c_str(), false) && result; + result = FileSystem::CreateDirectoryPath(CheatsNI.c_str(), false) && result; result = FileSystem::CreateDirectoryPath(Covers.c_str(), false) && result; result = FileSystem::CreateDirectoryPath(GameSettings.c_str(), false) && result; result = FileSystem::CreateDirectoryPath(Cache.c_str(), false) && result; diff --git a/pcsx2/VMManager.cpp b/pcsx2/VMManager.cpp index b2b24419f0..57bcc600fe 100644 --- a/pcsx2/VMManager.cpp +++ b/pcsx2/VMManager.cpp @@ -119,6 +119,9 @@ static std::string s_elf_override; static u32 s_active_game_fixes = 0; static std::vector s_widescreen_cheats_data; static bool s_widescreen_cheats_loaded = false; +static std::vector s_no_interlacing_cheats_data; +static bool s_no_interlacing_cheats_loaded = false; +static u32 s_active_no_interlacing_patches = 0; static s32 s_current_save_slot = 1; static u32 s_frame_advance_count = 0; static u32 s_mxcsr_saved; @@ -234,6 +237,8 @@ void VMManager::Internal::ReleaseMemory() { std::vector().swap(s_widescreen_cheats_data); s_widescreen_cheats_loaded = false; + std::vector().swap(s_no_interlacing_cheats_data); + s_no_interlacing_cheats_loaded = false; s_vm_memory->DecommitAll(); s_vm_memory->ReleaseAll(); @@ -265,6 +270,10 @@ void VMManager::LoadSettings() EmuConfig.GS.MaskUserHacks(); EmuConfig.GS.MaskUpscalingHacks(); + // Disable interlacing if we have no-interlacing patches active. + if (s_active_no_interlacing_patches > 0 && EmuConfig.GS.InterlaceMode == GSInterlaceMode::Automatic) + EmuConfig.GS.InterlaceMode = GSInterlaceMode::Off; + // Force MTVU off when playing back GS dumps, it doesn't get used. if (GSDumpReplayer::IsReplayingDump()) EmuConfig.Speedhacks.vuThread = false; @@ -436,9 +445,52 @@ static void LoadPatches(const std::string& crc_string, bool show_messages, bool fmt::format_to(std::back_inserter(message), "{}{} widescreen patches", (patch_count > 0 || cheat_count > 0) ? " and " : "", ws_patch_count); } + // no-interlacing patches + if (EmuConfig.EnableNoInterlacingPatches && s_game_crc != 0) + { + if (s_active_no_interlacing_patches = LoadPatchesFromDir(crc_string, EmuFolders::CheatsNI, "No-interlacing patches", false)) + { + Console.WriteLn(Color_Gray, "Found no-interlacing patches in the cheats_ni folder --> skipping cheats_ni.zip"); + } + else + { + // No ws cheat files found at the cheats_ws folder, try the ws cheats zip file. + if (!s_no_interlacing_cheats_loaded) + { + s_no_interlacing_cheats_loaded = true; + + std::optional> data = Host::ReadResourceFile("cheats_ni.zip"); + if (data.has_value()) + s_no_interlacing_cheats_data = std::move(data.value()); + } + + if (!s_no_interlacing_cheats_data.empty()) + { + s_active_no_interlacing_patches = LoadPatchesFromZip(crc_string, s_no_interlacing_cheats_data.data(), s_no_interlacing_cheats_data.size()); + PatchesCon->WriteLn(Color_Green, "(No-Interlacing Cheats DB) Patches Loaded: %u", s_active_no_interlacing_patches); + } + } + + if (s_active_no_interlacing_patches > 0) + { + fmt::format_to(std::back_inserter(message), "{}{} no-interlacing patches", (patch_count > 0 || cheat_count > 0 || ws_patch_count > 0) ? " and " : "", s_active_no_interlacing_patches); + + // Disable interlacing in GS if active. + if (EmuConfig.GS.InterlaceMode == GSInterlaceMode::Automatic) + { + EmuConfig.GS.InterlaceMode = GSInterlaceMode::Off; + GetMTGS().ApplySettings(); + } + } + } + else + { + s_active_no_interlacing_patches = 0; + } + if (show_messages) { - if (cheat_count > 0 || ws_patch_count > 0) + if (cheat_count > 0 || ws_patch_count > 0 || s_active_no_interlacing_patches > 0) { message += " are active."; Host::AddKeyedOSDMessage("LoadPatches", std::move(message), 5.0f); @@ -823,6 +875,8 @@ void VMManager::Shutdown(bool save_resume_state) s_game_name.clear(); Host::OnGameChanged(s_disc_path, s_game_serial, s_game_name, 0); } + s_active_game_fixes = 0; + s_active_no_interlacing_patches = 0; UpdateGameSettingsLayer(); std::string().swap(s_elf_override); @@ -859,6 +913,9 @@ void VMManager::Reset() { const bool game_was_started = g_GameStarted; + s_active_game_fixes = 0; + s_active_no_interlacing_patches = 0; + SysClearExecutionCache(); memBindConditionalHandlers(); UpdateVSyncRate(); @@ -1375,8 +1432,12 @@ void VMManager::CheckForConfigChanges(const Pcsx2Config& old_config) CheckForDEV9ConfigChanges(old_config); CheckForMemoryCardConfigChanges(old_config); - if (EmuConfig.EnableCheats != old_config.EnableCheats || EmuConfig.EnableWideScreenPatches != old_config.EnableWideScreenPatches) + if (EmuConfig.EnableCheats != old_config.EnableCheats || + EmuConfig.EnableWideScreenPatches != old_config.EnableWideScreenPatches || + EmuConfig.EnableNoInterlacingPatches != old_config.EnableNoInterlacingPatches) + { VMManager::ReloadPatches(true); + } } void VMManager::ApplySettings()