diff --git a/src/core/core.cpp b/src/core/core.cpp index 1ed72a3d9..828cd3715 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -325,6 +325,7 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st status = ResultStatus::Success; m_emu_window = &emu_window; m_filepath = filepath; + self_delete_pending = false; // Reset counters and set time origin to current frame [[maybe_unused]] const PerfStats::Results result = GetAndResetPerfStats(); @@ -559,6 +560,10 @@ void System::Shutdown(bool is_deserializing) { memory.reset(); + if (self_delete_pending) + FileUtil::Delete(m_filepath); + self_delete_pending = false; + LOG_DEBUG(Core, "Shutdown OK"); } @@ -575,6 +580,11 @@ void System::Reset() { Shutdown(); + if (!m_chainloadpath.empty()) { + m_filepath = m_chainloadpath; + m_chainloadpath.clear(); + } + // Reload the system with the same setting [[maybe_unused]] const System::ResultStatus result = Load(*m_emu_window, m_filepath); diff --git a/src/core/core.h b/src/core/core.h index 1ea2d9b55..67399b487 100644 --- a/src/core/core.h +++ b/src/core/core.h @@ -126,7 +126,8 @@ public: bool SendSignal(Signal signal, u32 param = 0); /// Request reset of the system - void RequestReset() { + void RequestReset(const std::string& chainload = "") { + m_chainloadpath = chainload; SendSignal(Signal::Reset); } @@ -306,6 +307,15 @@ public: void LoadState(u32 slot); + /// Self delete ncch + bool SetSelfDelete(const std::string& file) { + if (m_filepath == file) { + self_delete_pending = true; + return true; + } + return false; + } + private: /** * Initialize the emulated system. @@ -376,7 +386,9 @@ private: /// Saved variables for reset Frontend::EmuWindow* m_emu_window; std::string m_filepath; + std::string m_chainloadpath; u64 title_id; + bool self_delete_pending; std::mutex signal_mutex; Signal current_signal; diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index f215d67ce..71a09e9e5 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -315,7 +315,14 @@ bool CIAFile::Close() const { if (abort) break; - FileUtil::Delete(GetTitleContentPath(media_type, old_tmd.GetTitleID(), old_index)); + // If the file to delete is the current launched rom, signal the system to delete + // the current rom instead of deleting it now, once all the handles to the file + // are closed. + std::string to_delete = + GetTitleContentPath(media_type, old_tmd.GetTitleID(), old_index); + if (!(Core::System::GetInstance().IsPoweredOn() && + Core::System::GetInstance().SetSelfDelete(to_delete))) + FileUtil::Delete(to_delete); } FileUtil::Delete(old_tmd_path); diff --git a/src/core/hle/service/apt/applet_manager.cpp b/src/core/hle/service/apt/applet_manager.cpp index 6416d3b16..73d4e6d89 100644 --- a/src/core/hle/service/apt/applet_manager.cpp +++ b/src/core/hle/service/apt/applet_manager.cpp @@ -4,6 +4,7 @@ #include "core/core.h" #include "core/hle/applets/applet.h" +#include "core/hle/service/am/am.h" #include "core/hle/service/apt/applet_manager.h" #include "core/hle/service/apt/errors.h" #include "core/hle/service/apt/ns.h" @@ -545,17 +546,30 @@ ResultCode AppletManager::DoApplicationJump(DeliverArg arg) { // prompts it to call GetProgramIdOnApplicationJump and // PrepareToStartApplication/StartApplication on the title to launch. - if (app_jump_parameters.next_title_id == app_jump_parameters.current_title_id) { - // Perform a soft-reset if we're trying to relaunch the same title. - // TODO(Subv): Note that this reboots the entire emulated system, a better way would be to - // simply re-launch the title without closing all services, but this would only work for - // installed titles since we have no way of getting the file path of an arbitrary game dump - // based only on the title id. - system.RequestReset(); - return RESULT_SUCCESS; + // Perform a soft-reset if we're trying to relaunch the same title. + // TODO(Subv): Note that this reboots the entire emulated system, a better way would be to + // simply re-launch the title without closing all services, but this would only work for + // installed titles since we have no way of getting the file path of an arbitrary game dump + // based only on the title id. + + std::string new_path = Service::AM::GetTitleContentPath(app_jump_parameters.next_media_type, + app_jump_parameters.next_title_id); + if (new_path.empty() || !FileUtil::Exists(new_path)) { + LOG_CRITICAL( + Service_APT, + "Failed to find title during application jump: {} Resetting current title instead.", + new_path); + new_path.clear(); } + system.RequestReset(new_path); + return RESULT_SUCCESS; + // Launch the title directly. + // The emulator does not suport terminating old processes, would require a lot of cleanup + // This code is left commented for when this is implemented, for now we cannot use NS + // as the old process resources would interfere with the new ones + /* auto process = NS::LaunchTitle(app_jump_parameters.next_media_type, app_jump_parameters.next_title_id); if (!process) { @@ -563,6 +577,7 @@ ResultCode AppletManager::DoApplicationJump(DeliverArg arg) { system.RequestShutdown(); } return RESULT_SUCCESS; + */ } void AppletManager::EnsureHomeMenuLoaded() {