diff --git a/Source/Core/Core/HW/DVDInterface.cpp b/Source/Core/Core/HW/DVDInterface.cpp index 3599634e8e..728fd8a8c7 100644 --- a/Source/Core/Core/HW/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVDInterface.cpp @@ -244,6 +244,8 @@ static CoreTiming::EventType* s_dtk; static u64 s_last_read_offset; static u64 s_last_read_time; +static std::string s_disc_path_to_insert; + static CoreTiming::EventType* s_eject_disc; static CoreTiming::EventType* s_insert_disc; @@ -289,9 +291,24 @@ void DoState(PointerWrap& p) p.Do(s_last_read_offset); p.Do(s_last_read_time); + p.Do(s_disc_path_to_insert); + p.Do(s_stop_at_track_end); DVDThread::DoState(p); + + // s_inserted_volume isn't savestated (because it points to + // files on the local system). Instead, we check that + // s_disc_inside matches the status of s_inserted_volume. + // This won't catch cases of having the wrong disc inserted, though. + // TODO: Check the game ID, disc number, revision? + if (s_disc_inside != (s_inserted_volume != nullptr)) + { + if (s_disc_inside) + PanicAlertT("An inserted disc was expected but not found."); + else + s_inserted_volume.reset(); + } } static u32 ProcessDTKSamples(short* tempPCM, u32 num_samples) @@ -389,6 +406,8 @@ void Init() s_last_read_offset = 0; s_last_read_time = 0; + s_disc_path_to_insert.clear(); + s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback); s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback); @@ -458,16 +477,16 @@ static void EjectDiscCallback(u64 userdata, s64 cyclesLate) static void InsertDiscCallback(u64 userdata, s64 cyclesLate) { const std::string& old_path = SConfig::GetInstance().m_strFilename; - std::string* new_path = reinterpret_cast(userdata); - if (!SetVolumeName(*new_path)) + if (!SetVolumeName(s_disc_path_to_insert)) { // Put back the old one SetVolumeName(old_path); - PanicAlertT("Invalid file"); + PanicAlertT("The disc that was about to be inserted couldn't be found."); } SetDiscInside(VolumeIsValid()); - delete new_path; + + s_disc_path_to_insert.clear(); } // Can only be called by the host thread @@ -484,11 +503,15 @@ void ChangeDiscAsHost(const std::string& new_path) // Can only be called by the CPU thread void ChangeDiscAsCPU(const std::string& new_path) { - // TODO: This is bad. Pointers in CoreTiming userdata require - // manual memory management and aren't savestate-safe. - u64 new_path_pointer = reinterpret_cast(new std::string(new_path)); + if (!s_disc_path_to_insert.empty()) + { + PanicAlertT("A disc is already about to be inserted."); + return; + } + + s_disc_path_to_insert = new_path; CoreTiming::ScheduleEvent(0, s_eject_disc); - CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), s_insert_disc, new_path_pointer); + CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), s_insert_disc); Movie::SignalDiscChange(new_path); } diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index 37e42ba94f..c8801a9373 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -70,7 +70,7 @@ static Common::Event g_compressAndDumpStateSyncEvent; static std::thread g_save_thread; // Don't forget to increase this after doing changes on the savestate system -static const u32 STATE_VERSION = 59; // Last changed in PR 3490 +static const u32 STATE_VERSION = 60; // Last changed in PR 4242 // Maps savestate versions to Dolphin versions. // Versions after 42 don't need to be added to this list,