mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Savestate: Don't break event callbacks when a save fails
CoreTiming::DoState replaced every event's callback with the anti-crash one in every mode, relying on each module's restore to put it back. A save that failed partway never got to those, and left the running game with events that break into the debugger. The missing-section fallbacks then also ran on the save: cheats and the mic re-registered events into the wrong slots, and achievements reset the runtime. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
9140bc9548
commit
2e5edcd298
4 files changed
+27
-15
No files matched your search
+10
-6
@@ -544,13 +544,17 @@ void DoState(PointerWrap &p) {
|
||||
return;
|
||||
}
|
||||
|
||||
// These (should) be filled in later by the modules.
|
||||
for (int i = 0; i < current; ++i) {
|
||||
event_types[i].callback = AntiCrashCallback;
|
||||
event_types[i].name = "INVALID EVENT";
|
||||
// These (should) be filled in later by the modules. Only when loading: a save that fails partway
|
||||
// wouldn't get to all the restores, and would leave the running game with broken events.
|
||||
if (p.mode == PointerWrap::MODE_READ) {
|
||||
for (int i = 0; i < current; ++i) {
|
||||
event_types[i].callback = AntiCrashCallback;
|
||||
event_types[i].name = "INVALID EVENT";
|
||||
}
|
||||
nextEventTypeRestoreId = n - 1;
|
||||
usedEventTypes.clear();
|
||||
}
|
||||
nextEventTypeRestoreId = n - 1;
|
||||
usedEventTypes.clear();
|
||||
// Needed in every pass, or each restore would look like a duplicate and get a new id.
|
||||
restoredEventTypes.clear();
|
||||
|
||||
if (s >= 3) {
|
||||
|
||||
+7
-4
@@ -270,10 +270,13 @@ void __CheatDoState(PointerWrap &p) {
|
||||
// CoreTiming::DoState has already replaced the queue with the state's, which has no cheat
|
||||
// event in it, so without scheduling one here hleCheat never runs again and cheats (plus
|
||||
// the enable/disable polling) stay dead for the rest of the session.
|
||||
CheatEvent = -1;
|
||||
CoreTiming::RestoreRegisterEvent(CheatEvent, "CheatEvent", &hleCheat);
|
||||
CoreTiming::RemoveEvent(CheatEvent);
|
||||
CoreTiming::ScheduleEvent(msToCycles(GetRefreshMs()), CheatEvent, 0);
|
||||
// (Not when a save failed earlier and every section after comes back missing.)
|
||||
if (p.mode == PointerWrap::MODE_READ) {
|
||||
CheatEvent = -1;
|
||||
CoreTiming::RestoreRegisterEvent(CheatEvent, "CheatEvent", &hleCheat);
|
||||
CoreTiming::RemoveEvent(CheatEvent);
|
||||
CoreTiming::ScheduleEvent(msToCycles(GetRefreshMs()), CheatEvent, 0);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -121,10 +121,12 @@ void __UsbMicShutdown() {
|
||||
void __UsbMicDoState(PointerWrap &p) {
|
||||
auto s = p.Section("sceUsbMic", 0, 3);
|
||||
if (!s) {
|
||||
// Still need to restore the event.
|
||||
eventMicBlockingResume = -1;
|
||||
CoreTiming::RestoreRegisterEvent(eventMicBlockingResume, "MicBlockingResume", &__MicBlockingResume);
|
||||
waitingThreads.clear();
|
||||
// Still need to restore the event (unless this is a save that failed earlier.)
|
||||
if (p.mode == p.MODE_READ) {
|
||||
eventMicBlockingResume = -1;
|
||||
CoreTiming::RestoreRegisterEvent(eventMicBlockingResume, "MicBlockingResume", &__MicBlockingResume);
|
||||
waitingThreads.clear();
|
||||
}
|
||||
return;
|
||||
}
|
||||
bool isMicStartedNow = Microphone::isMicStarted();
|
||||
|
||||
@@ -877,7 +877,10 @@ void Idle() {
|
||||
void DoState(PointerWrap &p) {
|
||||
auto sw = p.Section("Achievements", 0, 1);
|
||||
if (!sw) {
|
||||
// Save state is missing the section.
|
||||
// Save state is missing the section, or this is a save that failed earlier.
|
||||
if (p.mode != PointerWrap::MODE_READ) {
|
||||
return;
|
||||
}
|
||||
// Reset the runtime.
|
||||
if (HasAchievementsOrLeaderboards()) {
|
||||
auto ac = GetI18NCategory(I18NCat::ACHIEVEMENTS);
|
||||
|
||||
Reference in new issue
Block a user