Achievements: Use big picture to confirm HC mode disable

This commit is contained in:
Stenzek 2023-11-27 01:23:02 +10:00 committed by Connor McLaughlin
parent 8a93c5696f
commit acb45459f5
7 changed files with 146 additions and 64 deletions

View File

@ -392,13 +392,33 @@ void EmuThread::run()
// Main CPU thread loop. // Main CPU thread loop.
while (!m_shutdown_flag.load()) while (!m_shutdown_flag.load())
{ {
if (!VMManager::HasValidVM()) switch (VMManager::GetState())
{ {
m_event_loop->exec(); case VMState::Initializing:
continue; pxFailRel("Shouldn't be in the starting state");
} continue;
executeVM(); case VMState::Shutdown:
case VMState::Paused:
m_event_loop->exec();
continue;
case VMState::Running:
m_event_loop->processEvents(QEventLoop::AllEvents);
VMManager::Execute();
continue;
case VMState::Resetting:
VMManager::Reset();
continue;
case VMState::Stopping:
destroyVM();
continue;
default:
continue;
}
} }
// Teardown in reverse order. // Teardown in reverse order.
@ -423,40 +443,6 @@ void EmuThread::destroyVM()
m_save_state_on_shutdown = false; m_save_state_on_shutdown = false;
} }
void EmuThread::executeVM()
{
for (;;)
{
switch (VMManager::GetState())
{
case VMState::Initializing:
pxFailRel("Shouldn't be in the starting state state");
continue;
case VMState::Paused:
m_event_loop->exec();
continue;
case VMState::Running:
m_event_loop->processEvents(QEventLoop::AllEvents);
VMManager::Execute();
continue;
case VMState::Resetting:
VMManager::Reset();
continue;
case VMState::Stopping:
destroyVM();
m_event_loop->processEvents(QEventLoop::AllEvents);
return;
default:
continue;
}
}
}
void EmuThread::createBackgroundControllerPollTimer() void EmuThread::createBackgroundControllerPollTimer()
{ {
pxAssert(!m_background_controller_polling_timer); pxAssert(!m_background_controller_polling_timer);

View File

@ -194,7 +194,6 @@ private:
static constexpr u32 FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL = 8; static constexpr u32 FULLSCREEN_UI_CONTROLLER_POLLING_INTERVAL = 8;
void destroyVM(); void destroyVM();
void executeVM();
void createBackgroundControllerPollTimer(); void createBackgroundControllerPollTimer();
void destroyBackgroundControllerPollTimer(); void destroyBackgroundControllerPollTimer();

View File

@ -1825,6 +1825,43 @@ bool Achievements::ConfirmHardcoreModeDisable(const char* trigger)
return true; return true;
} }
void Achievements::ConfirmHardcoreModeDisableAsync(const char* trigger, std::function<void(bool)> callback)
{
#ifdef ENABLE_RAINTEGRATION
if (IsUsingRAIntegration())
{
const bool result = (RA_WarnDisableHardcore(trigger) != 0);
callback(result);
return;
}
#endif
if (!FullscreenUI::Initialize())
{
Host::AddOSDMessage(fmt::format(TRANSLATE_FS("Cannot {} while hardcode mode is active.", trigger)),
Host::OSD_WARNING_DURATION);
callback(false);
return;
}
auto real_callback = [callback = std::move(callback)](bool res) mutable {
// don't run the callback in the middle of rendering the UI
Host::RunOnCPUThread([callback = std::move(callback), res]() {
if (res)
DisableHardcoreMode();
callback(res);
});
};
ImGuiFullscreen::OpenConfirmMessageDialog(
TRANSLATE_STR("Achievements", "Confirm Hardcore Mode"),
fmt::format(TRANSLATE_FS("Achievements", "{0} cannot be performed while hardcore mode is active. Do you "
"want to disable hardcore mode? {0} will be cancelled if you select No."),
trigger),
std::move(real_callback), fmt::format(ICON_FA_CHECK " {}", TRANSLATE_SV("Achievements", "Yes")),
fmt::format(ICON_FA_TIMES " {}", TRANSLATE_SV("Achievements", "No")));
}
void Achievements::ClearUIState() void Achievements::ClearUIState()
{ {
if (FullscreenUI::IsAchievementsWindowOpen() || FullscreenUI::IsLeaderboardsWindowOpen()) if (FullscreenUI::IsAchievementsWindowOpen() || FullscreenUI::IsLeaderboardsWindowOpen())

View File

@ -19,6 +19,7 @@
#include "Config.h" #include "Config.h"
#include <functional>
#include <mutex> #include <mutex>
#include <string> #include <string>
#include <utility> #include <utility>
@ -83,6 +84,7 @@ namespace Achievements
/// Prompts the user to disable hardcore mode, if they agree, returns true. /// Prompts the user to disable hardcore mode, if they agree, returns true.
bool ConfirmHardcoreModeDisable(const char* trigger); bool ConfirmHardcoreModeDisable(const char* trigger);
void ConfirmHardcoreModeDisableAsync(const char* trigger, std::function<void(bool)> callback);
/// Returns true if hardcore mode is active, and functionality should be restricted. /// Returns true if hardcore mode is active, and functionality should be restricted.
bool IsHardcoreModeActive(); bool IsHardcoreModeActive();

View File

@ -855,17 +855,12 @@ void FullscreenUI::DoStartPath(const std::string& path, std::optional<s32> state
params.fast_boot = fast_boot; params.fast_boot = fast_boot;
// switch to nothing, we'll get brought back if init fails // switch to nothing, we'll get brought back if init fails
const MainWindowType prev_window = s_current_main_window; Host::RunOnCPUThread([params = std::move(params)]() {
s_current_main_window = MainWindowType::None;
Host::RunOnCPUThread([params = std::move(params), prev_window]() {
if (VMManager::HasValidVM()) if (VMManager::HasValidVM())
return; return;
if (VMManager::Initialize(std::move(params))) if (VMManager::Initialize(std::move(params)))
VMManager::SetState(VMState::Running); VMManager::SetState(VMState::Running);
else
s_current_main_window = prev_window;
}); });
} }
@ -5514,6 +5509,18 @@ void FullscreenUI::DrawGameListWindow()
default: default:
break; break;
} }
if (VMManager::GetState() != VMState::Shutdown)
{
// Dummy window to prevent interacting with the game list while loading.
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize);
ImGui::SetNextWindowPos(ImVec2(0, 0));
ImGui::SetNextWindowBgAlpha(0.25f);
ImGui::Begin("##dummy", nullptr, ImGuiWindowFlags_NoDecoration);
ImGui::End();
ImGui::PopStyleColor();
}
} }
void FullscreenUI::DrawGameList(const ImVec2& heading_size) void FullscreenUI::DrawGameList(const ImVec2& heading_size)

View File

@ -527,7 +527,7 @@ void VMManager::ApplyGameFixes()
game->applyGameFixes(EmuConfig, EmuConfig.EnableGameFixes); game->applyGameFixes(EmuConfig, EmuConfig.EnableGameFixes);
game->applyGSHardwareFixes(EmuConfig.GS); game->applyGSHardwareFixes(EmuConfig.GS);
// Re-remove upscaling fixes, make sure they don't apply at native res. // Re-remove upscaling fixes, make sure they don't apply at native res.
// We do this in LoadCoreSettings(), but game fixes get applied afterwards because of the unsafe warning. // We do this in LoadCoreSettings(), but game fixes get applied afterwards because of the unsafe warning.
EmuConfig.GS.MaskUpscalingHacks(); EmuConfig.GS.MaskUpscalingHacks();
@ -658,7 +658,7 @@ void VMManager::Internal::UpdateEmuFolders()
AutoEject::SetAll(); AutoEject::SetAll();
if(!GSDumpReplayer::IsReplayingDump()) if (!GSDumpReplayer::IsReplayingDump())
FileMcd_Reopen(memcardFilters.empty() ? s_disc_serial : memcardFilters); FileMcd_Reopen(memcardFilters.empty() ? s_disc_serial : memcardFilters);
} }
@ -1085,6 +1085,12 @@ bool VMManager::Initialize(VMBootParameters boot_params)
s_elf_override = {}; s_elf_override = {};
ClearELFInfo(); ClearELFInfo();
ClearDiscDetails(); ClearDiscDetails();
Achievements::GameChanged(0, 0);
FullscreenUI::GameChanged(s_title, std::string(), s_disc_serial, 0, 0);
UpdateDiscordPresence();
Host::OnGameChanged(s_title, std::string(), std::string(), s_disc_serial, 0, 0);
UpdateGameSettingsLayer(); UpdateGameSettingsLayer();
s_state.store(VMState::Shutdown, std::memory_order_release); s_state.store(VMState::Shutdown, std::memory_order_release);
Host::OnVMDestroyed(); Host::OnVMDestroyed();
@ -1184,7 +1190,6 @@ bool VMManager::Initialize(VMBootParameters boot_params)
if (!FileSystem::FileExists(s_elf_override.c_str())) if (!FileSystem::FileExists(s_elf_override.c_str()))
{ {
Host::ReportErrorAsync("Error", fmt::format("Requested boot ELF '{}' does not exist.", s_elf_override)); Host::ReportErrorAsync("Error", fmt::format("Requested boot ELF '{}' does not exist.", s_elf_override));
DoCDVDclose();
return false; return false;
} }
@ -1200,11 +1205,34 @@ bool VMManager::Initialize(VMBootParameters boot_params)
} }
// Check for resuming with hardcore mode. // Check for resuming with hardcore mode.
Achievements::ResetHardcoreMode(); // Why do we need the boot param? Because we need some way of telling BootSystem() that
if (!state_to_load.empty() && Achievements::IsHardcoreModeActive() && // the user allowed HC mode to be disabled, because otherwise we'll ResetHardcoreMode()
!Achievements::ConfirmHardcoreModeDisable(TRANSLATE("VMManager", "Resuming state"))) // and send ourselves into an infinite loop.
if (boot_params.disable_achievements_hardcore_mode)
Achievements::DisableHardcoreMode();
else
Achievements::ResetHardcoreMode();
if (!state_to_load.empty() && Achievements::IsHardcoreModeActive())
{ {
return false; if (FullscreenUI::IsInitialized())
{
boot_params.elf_override = std::move(s_elf_override);
boot_params.save_state = std::move(state_to_load);
boot_params.disable_achievements_hardcore_mode = true;
s_elf_override = {};
Achievements::ConfirmHardcoreModeDisableAsync(TRANSLATE("VMManager", "Resuming state"),
[boot_params = std::move(boot_params)](bool approved) mutable {
if (approved && Initialize(std::move(boot_params)))
SetState(VMState::Running);
});
return false;
}
else if (!Achievements::ConfirmHardcoreModeDisable(TRANSLATE("VMManager", "Resuming state")))
{
return false;
}
} }
s_limiter_mode = GetInitialLimiterMode(); s_limiter_mode = GetInitialLimiterMode();
@ -1233,7 +1261,7 @@ bool VMManager::Initialize(VMBootParameters boot_params)
} }
ScopedGuard close_spu2(&SPU2::Close); ScopedGuard close_spu2(&SPU2::Close);
Console.WriteLn("Initializing Pad..."); Console.WriteLn("Initializing Pad...");
if (!Pad::Initialize()) if (!Pad::Initialize())
{ {
@ -1706,8 +1734,15 @@ u32 VMManager::DeleteSaveStates(const char* game_serial, u32 game_crc, bool also
bool VMManager::LoadState(const char* filename) bool VMManager::LoadState(const char* filename)
{ {
if (Achievements::IsHardcoreModeActive() && !Achievements::ConfirmHardcoreModeDisable(TRANSLATE("VMManager", "Loading state"))) if (Achievements::IsHardcoreModeActive())
{
Achievements::ConfirmHardcoreModeDisableAsync(TRANSLATE("VMManager", "Loading state"),
[filename = std::string(filename)](bool approved) {
if (approved)
LoadState(filename.c_str());
});
return false; return false;
}
// TODO: Save the current state so we don't need to reset. // TODO: Save the current state so we don't need to reset.
if (DoLoadState(filename)) if (DoLoadState(filename))
@ -1719,7 +1754,7 @@ bool VMManager::LoadState(const char* filename)
bool VMManager::LoadStateFromSlot(s32 slot) bool VMManager::LoadStateFromSlot(s32 slot)
{ {
const std::string filename(GetCurrentSaveStateFileName(slot)); const std::string filename = GetCurrentSaveStateFileName(slot);
if (filename.empty()) if (filename.empty())
{ {
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE, Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE,
@ -1728,8 +1763,15 @@ bool VMManager::LoadStateFromSlot(s32 slot)
return false; return false;
} }
if (Achievements::IsHardcoreModeActive() && !Achievements::ConfirmHardcoreModeDisable(TRANSLATE("VMManager", "Loading state"))) if (Achievements::IsHardcoreModeActive())
{
Achievements::ConfirmHardcoreModeDisableAsync(TRANSLATE("VMManager", "Loading state"),
[slot](bool approved) {
if (approved)
LoadStateFromSlot(slot);
});
return false; return false;
}
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_FOLDER_OPEN, Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_FOLDER_OPEN,
fmt::format(TRANSLATE_FS("VMManager", "Loading state from slot {}..."), slot), Host::OSD_QUICK_DURATION); fmt::format(TRANSLATE_FS("VMManager", "Loading state from slot {}..."), slot), Host::OSD_QUICK_DURATION);
@ -1916,8 +1958,16 @@ void VMManager::FrameAdvance(u32 num_frames /*= 1*/)
if (!HasValidVM()) if (!HasValidVM())
return; return;
if (Achievements::IsHardcoreModeActive() && !Achievements::ConfirmHardcoreModeDisable(TRANSLATE("VMManager", "Frame advancing"))) if (Achievements::IsHardcoreModeActive())
{
Achievements::ConfirmHardcoreModeDisableAsync(TRANSLATE("VMManager", "Frame advancing"),
[num_frames](bool approved) {
if (approved)
FrameAdvance(num_frames);
});
return; return;
}
s_frame_advance_count = num_frames; s_frame_advance_count = num_frames;
SetState(VMState::Running); SetState(VMState::Running);
@ -1961,7 +2011,7 @@ bool VMManager::ChangeDisc(CDVD_SourceType source, std::string path)
if (!DoCDVDopen(&error)) if (!DoCDVDopen(&error))
{ {
Host::AddIconOSDMessage("ChangeDisc", ICON_FA_COMPACT_DISC, Host::AddIconOSDMessage("ChangeDisc", ICON_FA_COMPACT_DISC,
fmt::format(TRANSLATE_FS("VMManager", "Failed to switch back to old disc image. Removing disc.\nError was: {}"), fmt::format(TRANSLATE_FS("VMManager", "Failed to switch back to old disc image. Removing disc.\nError was: {}"),
error.GetDescription()), error.GetDescription()),
Host::OSD_CRITICAL_ERROR_DURATION); Host::OSD_CRITICAL_ERROR_DURATION);
CDVDsys_ChangeSource(CDVD_SourceType::NoDisc); CDVDsys_ChangeSource(CDVD_SourceType::NoDisc);
@ -2263,7 +2313,7 @@ void VMManager::CheckForGSConfigChanges(const Pcsx2Config& old_config)
} }
else if (EmuConfig.GS.VsyncEnable != old_config.GS.VsyncEnable) else if (EmuConfig.GS.VsyncEnable != old_config.GS.VsyncEnable)
{ {
// Still need to update target speed, because of sync-to-host-refresh. // Still need to update target speed, because of sync-to-host-refresh.
UpdateTargetSpeed(); UpdateTargetSpeed();
} }
@ -2482,8 +2532,7 @@ void VMManager::WarnAboutUnsafeSettings()
return; return;
std::string messages; std::string messages;
auto append = [&messages](const char* icon, const std::string_view& msg) auto append = [&messages](const char* icon, const std::string_view& msg) {
{
messages += icon; messages += icon;
messages += ' '; messages += ' ';
messages += msg; messages += msg;
@ -2860,11 +2909,12 @@ static void InitializeCPUInfo()
s_big_cores = 0; s_big_cores = 0;
s_small_cores = 0; s_small_cores = 0;
std::vector<DarwinMisc::CPUClass> classes = DarwinMisc::GetCPUClasses(); std::vector<DarwinMisc::CPUClass> classes = DarwinMisc::GetCPUClasses();
for (size_t i = 0; i < classes.size(); i++) { for (size_t i = 0; i < classes.size(); i++)
{
const DarwinMisc::CPUClass& cls = classes[i]; const DarwinMisc::CPUClass& cls = classes[i];
const bool is_big = i == 0 || i < classes.size() - 1; // Assume only one group is small const bool is_big = i == 0 || i < classes.size() - 1; // Assume only one group is small
DevCon.WriteLn("(VMManager) Found %u physical cores and %u logical cores in perf level %u (%s), assuming %s", DevCon.WriteLn("(VMManager) Found %u physical cores and %u logical cores in perf level %u (%s), assuming %s",
cls.num_physical, cls.num_logical, i, cls.name.c_str(), is_big ? "big" : "small"); cls.num_physical, cls.num_logical, i, cls.name.c_str(), is_big ? "big" : "small");
(is_big ? s_big_cores : s_small_cores) += cls.num_physical; (is_big ? s_big_cores : s_small_cores) += cls.num_physical;
} }
} }

View File

@ -47,6 +47,7 @@ struct VMBootParameters
std::optional<bool> fast_boot; std::optional<bool> fast_boot;
std::optional<bool> fullscreen; std::optional<bool> fullscreen;
bool disable_achievements_hardcore_mode = false;
}; };
namespace VMManager namespace VMManager