diff --git a/rpcs3/Emu/System.cpp b/rpcs3/Emu/System.cpp index 7d12405f44..ea9092f597 100644 --- a/rpcs3/Emu/System.cpp +++ b/rpcs3/Emu/System.cpp @@ -142,6 +142,7 @@ void fmt_class_string<game_boot_result>::format(std::string& out, u64 arg) case game_boot_result::savestate_version_unsupported: return "Savestate versioning data differs from your RPCS3 build.\nTry to use an older or newer RPCS3 build.\nEspecially if you know the build that created the savestate."; case game_boot_result::still_running: return "Game is still running"; case game_boot_result::already_added: return "Game was already added"; + case game_boot_result::currently_restricted: return "Booting is restricted at the time being"; } return unknown; }); @@ -802,7 +803,7 @@ std::string Emulator::GetBackgroundPicturePath() const bool Emulator::BootRsxCapture(const std::string& path) { - if (m_state != system_state::stopped) + if (m_state != system_state::stopped || m_restrict_emu_state_change) { return false; } @@ -928,6 +929,11 @@ game_boot_result Emulator::GetElfPathFromDir(std::string& elf_path, const std::s game_boot_result Emulator::BootGame(const std::string& path, const std::string& title_id, bool direct, cfg_mode config_mode, const std::string& config_path) { + if (m_restrict_emu_state_change) + { + return game_boot_result::currently_restricted; + } + auto save_args = std::make_tuple(m_path, m_path_original, argv, envp, data, disc, klic, hdd1, m_config_mode, m_config_path); auto restore_on_no_boot = [&](game_boot_result result) @@ -978,11 +984,18 @@ void Emulator::SetForceBoot(bool force_boot) game_boot_result Emulator::Load(const std::string& title_id, bool is_disc_patch, usz recursion_count) { + if (m_restrict_emu_state_change) + { + return game_boot_result::currently_restricted; + } + if (m_state != system_state::stopped) { return game_boot_result::still_running; } + const auto guard = MakeEmulationStateGuard(); + // Enable logging rpcs3::utils::configure_logs(true); diff --git a/rpcs3/Emu/System.h b/rpcs3/Emu/System.h index 987455e1ea..c2b68b9253 100644 --- a/rpcs3/Emu/System.h +++ b/rpcs3/Emu/System.h @@ -57,6 +57,7 @@ enum class game_boot_result : u32 savestate_version_unsupported, still_running, already_added, + currently_restricted, }; constexpr bool is_error(game_boot_result res) @@ -123,6 +124,7 @@ class Emulator final atomic_t<u64> m_pause_amend_time{0}; // increased when resumed atomic_t<u64> m_stop_ctr{1}; // Increments when emulation is stopped atomic_t<bool> m_emu_state_close_pending = false; + atomic_t<u64> m_restrict_emu_state_change{0}; games_config m_games_config; @@ -206,8 +208,13 @@ public: enum class stop_counter_t : u64{}; // Returns a different value each time we start a new emulation. - stop_counter_t GetEmulationIdentifier() const + stop_counter_t GetEmulationIdentifier(bool subtract_one = false) const { + if (subtract_one) + { + return stop_counter_t{m_stop_ctr - 1}; + } + return stop_counter_t{+m_stop_ctr}; } @@ -338,6 +345,41 @@ public: return m_config_mode == cfg_mode::continuous; } + class emulation_state_guard_t + { + class Emulator* _this = nullptr; + bool active = true; + + public: + explicit emulation_state_guard_t(Emulator* this0) noexcept + : _this(this0) + { + _this->m_restrict_emu_state_change++; + } + + ~emulation_state_guard_t() noexcept + { + if (active) + { + _this->m_restrict_emu_state_change--; + } + } + + emulation_state_guard_t(emulation_state_guard_t&& rhs) noexcept + { + _this = rhs._this; + active = std::exchange(rhs.active, false); + } + + emulation_state_guard_t& operator=(const emulation_state_guard_t&) = delete; + emulation_state_guard_t(const emulation_state_guard_t&) = delete; + }; + + emulation_state_guard_t MakeEmulationStateGuard() + { + return emulation_state_guard_t{this}; + } + game_boot_result BootGame(const std::string& path, const std::string& title_id = "", bool direct = false, cfg_mode config_mode = cfg_mode::custom, const std::string& config_path = ""); bool BootRsxCapture(const std::string& path); @@ -349,6 +391,11 @@ public: void FixGuestTime(); void FinalizeRunRequest(); + bool IsBootingRestricted() const + { + return m_restrict_emu_state_change != 0; + } + private: struct savestate_stage { diff --git a/rpcs3/rpcs3qt/gui_settings.cpp b/rpcs3/rpcs3qt/gui_settings.cpp index fc66dfccd9..54ed12391f 100644 --- a/rpcs3/rpcs3qt/gui_settings.cpp +++ b/rpcs3/rpcs3qt/gui_settings.cpp @@ -195,13 +195,17 @@ void gui_settings::ShowInfoBox(const QString& title, const QString& text, const bool gui_settings::GetBootConfirmation(QWidget* parent, const gui_save& gui_save_entry) { - auto info = Emu.GetEmulationIdentifier(); + // Ensure no game has booted inbetween + const auto guard = Emu.MakeEmulationStateGuard(); + + const auto info = Emu.GetEmulationIdentifier(); + const auto old_status = Emu.GetStatus(false); qt_events_aware_op(16, [&]() { if (Emu.GetStatus(false) != system_state::stopping) { - ensure(info == Emu.GetEmulationIdentifier()); + ensure(info == Emu.GetEmulationIdentifier(old_status == system_state::stopping ? true : false)); return true; } diff --git a/rpcs3/rpcs3qt/main_window.cpp b/rpcs3/rpcs3qt/main_window.cpp index 8648b41d0c..9c02b4a0d9 100644 --- a/rpcs3/rpcs3qt/main_window.cpp +++ b/rpcs3/rpcs3qt/main_window.cpp @@ -562,6 +562,7 @@ void main_window::show_boot_error(game_boot_result status) break; case game_boot_result::firmware_missing: // Handled elsewhere case game_boot_result::already_added: // Handled elsewhere + case game_boot_result::currently_restricted: case game_boot_result::no_errors: return; case game_boot_result::generic_error: @@ -576,12 +577,18 @@ void main_window::show_boot_error(game_boot_result status) msg->setTextFormat(Qt::RichText); msg->setStandardButtons(QMessageBox::Ok); msg->setText(tr("Booting failed: %1 %2").arg(message).arg(link)); + msg->setParent(this); msg->setAttribute(Qt::WA_DeleteOnClose); msg->open(); } void main_window::Boot(const std::string& path, const std::string& title_id, bool direct, bool refresh_list, cfg_mode config_mode, const std::string& config_path) { + if (Emu.IsBootingRestricted()) + { + return; + } + if (!m_gui_settings->GetBootConfirmation(this, gui::ib_confirm_boot)) { return; @@ -3776,6 +3783,11 @@ void main_window::RemoveFirmwareCache() void main_window::CreateFirmwareCache() { + if (Emu.IsBootingRestricted()) + { + return; + } + if (!m_gui_settings->GetBootConfirmation(this)) { return; @@ -4092,6 +4104,11 @@ void main_window::dropEvent(QDropEvent* event) } case drop_type::drop_game: // import valid games to gamelist (games.yaml) { + if (Emu.IsBootingRestricted()) + { + return; + } + if (!m_gui_settings->GetBootConfirmation(this)) { return;