Skip to content

Commit

Permalink
System: Add taints to save states
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
stenzek committed Oct 18, 2024
1 parent 2aea065 commit baa9065
Show file tree
Hide file tree
Showing 5 changed files with 160 additions and 15 deletions.
46 changes: 32 additions & 14 deletions src/core/cheats.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -862,35 +866,39 @@ 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.
// Except when it's just GameDB.
const size_t new_count = s_frame_end_codes.size();
if (verbose || (verbose_if_changed && prev_count != new_count))
{
if (patch_count > 0)
if (s_active_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);
System::SetTaint(System::Taint::Patches);
Host::AddIconOSDMessage(
"LoadPatches", ICON_FA_BAND_AID,
TRANSLATE_PLURAL_STR("Cheats", "%n game patches are active.", "OSD Message", s_active_patch_count),
Host::OSD_INFO_DURATION);
}
if (cheat_count > 0)
if (s_active_cheat_count > 0)
{
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);
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 (patch_count == 0)
else if (s_active_patch_count == 0)
{
Host::RemoveKeyedOSDMessage("LoadPatches");
Host::AddIconOSDMessage("LoadCheats", ICON_FA_BAND_AID,
Expand Down Expand Up @@ -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
//////////////////////////////////////////////////////////////////////////
Expand Down
6 changes: 6 additions & 0 deletions src/core/cheats.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/core/save_state_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
103 changes: 103 additions & 0 deletions src/core/system.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -2039,6 +2085,7 @@ void System::DestroySystem()
Host::ReleaseGPUDevice();
}

s_taints = 0;
s_bios_hash = {};
s_bios_image_info = nullptr;
s_exe_override = {};
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -2600,6 +2652,9 @@ void System::InternalReset()
if (IsShutdown())
return;

// reset and clear taints
SetTaintsFromSettings();

TimingEvents::Reset();
CPU::Reset();
CPU::CodeCache::Reset();
Expand Down Expand Up @@ -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;
Expand Down
18 changes: 18 additions & 0 deletions src/core/system.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;
Expand Down

0 comments on commit baa9065

Please sign in to comment.