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.
while (!m_shutdown_flag.load())
{
if (!VMManager::HasValidVM())
switch (VMManager::GetState())
{
m_event_loop->exec();
continue;
}
case VMState::Initializing:
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.
@ -423,40 +443,6 @@ void EmuThread::destroyVM()
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()
{
pxAssert(!m_background_controller_polling_timer);

View File

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

View File

@ -1825,6 +1825,43 @@ bool Achievements::ConfirmHardcoreModeDisable(const char* trigger)
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()
{
if (FullscreenUI::IsAchievementsWindowOpen() || FullscreenUI::IsLeaderboardsWindowOpen())

View File

@ -19,6 +19,7 @@
#include "Config.h"
#include <functional>
#include <mutex>
#include <string>
#include <utility>
@ -83,6 +84,7 @@ namespace Achievements
/// Prompts the user to disable hardcore mode, if they agree, returns true.
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.
bool IsHardcoreModeActive();

View File

@ -855,17 +855,12 @@ void FullscreenUI::DoStartPath(const std::string& path, std::optional<s32> state
params.fast_boot = fast_boot;
// switch to nothing, we'll get brought back if init fails
const MainWindowType prev_window = s_current_main_window;
s_current_main_window = MainWindowType::None;
Host::RunOnCPUThread([params = std::move(params), prev_window]() {
Host::RunOnCPUThread([params = std::move(params)]() {
if (VMManager::HasValidVM())
return;
if (VMManager::Initialize(std::move(params)))
VMManager::SetState(VMState::Running);
else
s_current_main_window = prev_window;
});
}
@ -5514,6 +5509,18 @@ void FullscreenUI::DrawGameListWindow()
default:
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)

View File

@ -527,7 +527,7 @@ void VMManager::ApplyGameFixes()
game->applyGameFixes(EmuConfig, EmuConfig.EnableGameFixes);
game->applyGSHardwareFixes(EmuConfig.GS);
// 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.
EmuConfig.GS.MaskUpscalingHacks();
@ -658,7 +658,7 @@ void VMManager::Internal::UpdateEmuFolders()
AutoEject::SetAll();
if(!GSDumpReplayer::IsReplayingDump())
if (!GSDumpReplayer::IsReplayingDump())
FileMcd_Reopen(memcardFilters.empty() ? s_disc_serial : memcardFilters);
}
@ -1085,6 +1085,12 @@ bool VMManager::Initialize(VMBootParameters boot_params)
s_elf_override = {};
ClearELFInfo();
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();
s_state.store(VMState::Shutdown, std::memory_order_release);
Host::OnVMDestroyed();
@ -1184,7 +1190,6 @@ bool VMManager::Initialize(VMBootParameters boot_params)
if (!FileSystem::FileExists(s_elf_override.c_str()))
{
Host::ReportErrorAsync("Error", fmt::format("Requested boot ELF '{}' does not exist.", s_elf_override));
DoCDVDclose();
return false;
}
@ -1200,11 +1205,34 @@ bool VMManager::Initialize(VMBootParameters boot_params)
}
// Check for resuming with hardcore mode.
Achievements::ResetHardcoreMode();
if (!state_to_load.empty() && Achievements::IsHardcoreModeActive() &&
!Achievements::ConfirmHardcoreModeDisable(TRANSLATE("VMManager", "Resuming state")))
// Why do we need the boot param? Because we need some way of telling BootSystem() that
// the user allowed HC mode to be disabled, because otherwise we'll ResetHardcoreMode()
// 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();
@ -1233,7 +1261,7 @@ bool VMManager::Initialize(VMBootParameters boot_params)
}
ScopedGuard close_spu2(&SPU2::Close);
Console.WriteLn("Initializing Pad...");
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)
{
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;
}
// TODO: Save the current state so we don't need to reset.
if (DoLoadState(filename))
@ -1719,7 +1754,7 @@ bool VMManager::LoadState(const char* filename)
bool VMManager::LoadStateFromSlot(s32 slot)
{
const std::string filename(GetCurrentSaveStateFileName(slot));
const std::string filename = GetCurrentSaveStateFileName(slot);
if (filename.empty())
{
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_EXCLAMATION_TRIANGLE,
@ -1728,8 +1763,15 @@ bool VMManager::LoadStateFromSlot(s32 slot)
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;
}
Host::AddIconOSDMessage("LoadStateFromSlot", ICON_FA_FOLDER_OPEN,
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())
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;
}
s_frame_advance_count = num_frames;
SetState(VMState::Running);
@ -1961,7 +2011,7 @@ bool VMManager::ChangeDisc(CDVD_SourceType source, std::string path)
if (!DoCDVDopen(&error))
{
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()),
Host::OSD_CRITICAL_ERROR_DURATION);
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)
{
// 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();
}
@ -2482,8 +2532,7 @@ void VMManager::WarnAboutUnsafeSettings()
return;
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 += ' ';
messages += msg;
@ -2860,11 +2909,12 @@ static void InitializeCPUInfo()
s_big_cores = 0;
s_small_cores = 0;
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 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",
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;
}
}

View File

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