System: Add taints to save states

This informs the user they are loading a save state that at some point
had potentially-game-breaking options enabled, and a reset is necessary
to clear them.
This commit is contained in:
Stenzek 2024-10-19 01:11:43 +10:00
parent 2aea06526c
commit baa9065d2e
No known key found for this signature in database
5 changed files with 161 additions and 16 deletions

View File

@ -237,6 +237,8 @@ static EnableCodeList s_enabled_patches;
static ActiveCodeList s_frame_end_codes;
static u32 s_active_patch_count = 0;
static u32 s_active_cheat_count = 0;
static bool s_patches_enabled = false;
static bool s_cheats_enabled = false;
static bool s_database_cheat_codes_enabled = false;
@ -828,6 +830,8 @@ void Cheats::ReloadCheats(bool reload_files, bool reload_enabled_list, bool verb
void Cheats::UnloadAll()
{
s_active_cheat_count = 0;
s_active_patch_count = 0;
s_frame_end_codes = ActiveCodeList();
s_enabled_patches = EnableCodeList();
s_enabled_cheats = EnableCodeList();
@ -862,14 +866,15 @@ void Cheats::UpdateActiveCodes(bool reload_enabled_list, bool verbose, bool verb
const size_t prev_count = s_frame_end_codes.size();
s_frame_end_codes.clear();
u32 patch_count = 0;
u32 cheat_count = 0;
s_active_patch_count = 0;
s_active_cheat_count = 0;
if (!g_settings.disable_all_enhancements)
{
const bool hc_mode_active = Achievements::IsHardcoreModeActive();
patch_count = EnableCheats(s_patch_codes, s_enabled_patches, "Patches", hc_mode_active);
cheat_count = AreCheatsEnabled() ? EnableCheats(s_cheat_codes, s_enabled_cheats, "Cheats", hc_mode_active) : 0;
s_active_patch_count = EnableCheats(s_patch_codes, s_enabled_patches, "Patches", hc_mode_active);
s_active_cheat_count =
AreCheatsEnabled() ? EnableCheats(s_cheat_codes, s_enabled_cheats, "Cheats", hc_mode_active) : 0;
}
// Display message on first boot when we load patches.
@ -877,20 +882,23 @@ void Cheats::UpdateActiveCodes(bool reload_enabled_list, bool verbose, bool verb
const size_t new_count = s_frame_end_codes.size();
if (verbose || (verbose_if_changed && prev_count != new_count))
{
if (patch_count > 0)
{
Host::AddIconOSDMessage("LoadPatches", ICON_FA_BAND_AID,
TRANSLATE_PLURAL_STR("Cheats", "%n game patches are active.", "OSD Message", patch_count),
Host::OSD_INFO_DURATION);
}
if (cheat_count > 0)
if (s_active_patch_count > 0)
{
System::SetTaint(System::Taint::Patches);
Host::AddIconOSDMessage(
"LoadCheats", ICON_EMOJI_WARNING,
TRANSLATE_PLURAL_STR("Cheats", "%n cheats are enabled. This may crash games.", "OSD Message", cheat_count),
Host::OSD_WARNING_DURATION);
"LoadPatches", ICON_FA_BAND_AID,
TRANSLATE_PLURAL_STR("Cheats", "%n game patches are active.", "OSD Message", s_active_patch_count),
Host::OSD_INFO_DURATION);
}
else if (patch_count == 0)
if (s_active_cheat_count > 0)
{
System::SetTaint(System::Taint::Cheats);
Host::AddIconOSDMessage("LoadCheats", ICON_EMOJI_WARNING,
TRANSLATE_PLURAL_STR("Cheats", "%n cheats are enabled. This may crash games.",
"OSD Message", s_active_cheat_count),
Host::OSD_WARNING_DURATION);
}
else if (s_active_patch_count == 0)
{
Host::RemoveKeyedOSDMessage("LoadPatches");
Host::AddIconOSDMessage("LoadCheats", ICON_FA_BAND_AID,
@ -936,6 +944,16 @@ bool Cheats::ApplyManualCode(const std::string_view name)
return false;
}
u32 Cheats::GetActivePatchCount()
{
return s_active_patch_count;
}
u32 Cheats::GetActiveCheatCount()
{
return s_active_cheat_count;
}
//////////////////////////////////////////////////////////////////////////
// File Parsing
//////////////////////////////////////////////////////////////////////////

View File

@ -143,6 +143,12 @@ extern bool EnumerateManualCodes(std::function<bool(const std::string& name)> ca
/// Invokes/applies the specified manually-activated code.
extern bool ApplyManualCode(const std::string_view name);
/// Returns the number of active patches.
extern u32 GetActivePatchCount();
/// Returns the number of active cheats.
extern u32 GetActiveCheatCount();
// Config sections/keys to use to enable patches.
extern const char* PATCHES_CONFIG_SECTION;
extern const char* CHEATS_CONFIG_SECTION;

View File

@ -6,7 +6,7 @@
#include "common/types.h"
static constexpr u32 SAVE_STATE_MAGIC = 0x43435544;
static constexpr u32 SAVE_STATE_VERSION = 74;
static constexpr u32 SAVE_STATE_VERSION = 75;
static constexpr u32 SAVE_STATE_MINIMUM_VERSION = 42;
static_assert(SAVE_STATE_VERSION >= SAVE_STATE_MINIMUM_VERSION);

View File

@ -151,6 +151,8 @@ static bool ShouldStartPaused();
/// Checks for settings changes, std::move() the old settings away for comparing beforehand.
static void CheckForSettingsChanges(const Settings& old_settings);
static void SetTaintsFromSettings();
static void WarnAboutStateTaints(u32 state_taints);
static void WarnAboutUnsafeSettings();
static void LogUnsafeSettingsToConsole(const SmallStringBase& messages);
@ -251,6 +253,7 @@ static u32 s_frame_number = 1;
static u32 s_internal_frame_number = 1;
static const BIOS::ImageInfo* s_bios_image_info = nullptr;
static BIOS::ImageInfo::Hash s_bios_hash = {};
static u32 s_taints = 0;
static std::string s_running_game_path;
static std::string s_running_game_serial;
@ -660,6 +663,49 @@ bool System::IsPALRegion()
return s_region == ConsoleRegion::PAL;
}
const char* System::GetTaintDisplayName(Taint taint)
{
static constexpr const std::array<const char*, static_cast<size_t>(Taint::MaxCount)> names = {{
TRANSLATE_DISAMBIG_NOOP("System", "CPU Overclock", "Taint"),
TRANSLATE_DISAMBIG_NOOP("System", "CD-ROM Read Speedup", "Taint"),
TRANSLATE_DISAMBIG_NOOP("System", "CD-ROM Seek Speedup", "Taint"),
TRANSLATE_DISAMBIG_NOOP("System", "Force Frame Timings", "Taint"),
TRANSLATE_DISAMBIG_NOOP("System", "8MB RAM", "Taint"),
TRANSLATE_DISAMBIG_NOOP("System", "Cheats", "Taint"),
TRANSLATE_DISAMBIG_NOOP("System", "Game Patches", "Taint"),
}};
return names[static_cast<size_t>(taint)];
}
const char* System::GetTaintName(Taint taint)
{
static constexpr const std::array<const char*, static_cast<size_t>(Taint::MaxCount)> names = {{
"CPUOverclock",
"CDROMReadSpeedup",
"CDROMSeekSpeedup",
"ForceFrameTimings",
"RAM8MB",
"Cheats",
"Patches",
}};
return names[static_cast<size_t>(taint)];
}
bool System::HasTaint(Taint taint)
{
return (s_taints & (1u << static_cast<u8>(taint))) != 0u;
}
void System::SetTaint(Taint taint)
{
if (!HasTaint(taint))
WARNING_LOG("Setting system taint: {}", GetTaintName(taint));
s_taints |= (1u << static_cast<u8>(taint));
}
TickCount System::GetMaxSliceTicks()
{
return s_max_slice_ticks;
@ -2039,6 +2085,7 @@ void System::DestroySystem()
Host::ReleaseGPUDevice();
}
s_taints = 0;
s_bios_hash = {};
s_bios_image_info = nullptr;
s_exe_override = {};
@ -2464,6 +2511,11 @@ bool System::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_di
sw.Do(&s_region);
}
u32 state_taints = s_taints;
sw.DoEx(&state_taints, 75, static_cast<u32>(0));
if (state_taints != s_taints) [[unlikely]]
WarnAboutStateTaints(state_taints);
sw.Do(&s_frame_number);
sw.Do(&s_internal_frame_number);
@ -2600,6 +2652,9 @@ void System::InternalReset()
if (IsShutdown())
return;
// reset and clear taints
SetTaintsFromSettings();
TimingEvents::Reset();
CPU::Reset();
CPU::CodeCache::Reset();
@ -4580,6 +4635,54 @@ void System::CheckForSettingsChanges(const Settings& old_settings)
}
}
void System::SetTaintsFromSettings()
{
s_taints = 0;
if (g_settings.cdrom_read_speedup > 1)
SetTaint(Taint::CDROMReadSpeedup);
if (g_settings.cdrom_seek_speedup > 1)
SetTaint(Taint::CDROMSeekSpeedup);
if (g_settings.cpu_overclock_active)
SetTaint(Taint::CPUOverclock);
if (g_settings.gpu_force_video_timing != ForceVideoTimingMode::Disabled)
SetTaint(Taint::ForceFrameTimings);
if (g_settings.enable_8mb_ram)
SetTaint(Taint::RAM8MB);
if (Cheats::GetActivePatchCount() > 0)
SetTaint(Taint::Patches);
if (Cheats::GetActiveCheatCount() > 0)
SetTaint(Taint::Cheats);
}
void System::WarnAboutStateTaints(u32 state_taints)
{
const u32 taints_active_in_file = state_taints & ~s_taints;
if (taints_active_in_file == 0)
return;
LargeString messages;
for (u32 i = 0; i < static_cast<u32>(Taint::MaxCount); i++)
{
if (!(taints_active_in_file & (1u << i)))
continue;
if (messages.empty())
{
messages.append_format(
"{} {}\n", ICON_EMOJI_WARNING,
TRANSLATE_SV("System", "This save state was created with the following tainted options, and may\n"
" be unstable. You will need to reset the system to clear any effects."));
}
messages.append(" \u2022 ");
messages.append(GetTaintDisplayName(static_cast<Taint>(i)));
messages.append('\n');
}
Host::AddKeyedOSDWarning("SystemTaintsFromState", std::string(messages.view()), Host::OSD_WARNING_DURATION);
}
void System::WarnAboutUnsafeSettings()
{
LargeString messages;

View File

@ -104,6 +104,18 @@ enum class BootMode
BootPSF,
};
enum class Taint : u8
{
CPUOverclock,
CDROMReadSpeedup,
CDROMSeekSpeedup,
ForceFrameTimings,
RAM8MB,
Cheats,
Patches,
MaxCount,
};
extern TickCount g_ticks_per_second;
/// Returns true if the filename is a PlayStation executable we can inject.
@ -156,6 +168,12 @@ ConsoleRegion GetRegion();
DiscRegion GetDiscRegion();
bool IsPALRegion();
/// Taints - flags that are set on the system and only cleared on reset.
const char* GetTaintDisplayName(Taint taint);
const char* GetTaintName(Taint taint);
bool HasTaint(Taint taint);
void SetTaint(Taint taint);
ALWAYS_INLINE TickCount GetTicksPerSecond()
{
return g_ticks_per_second;