diff --git a/src/BizHawk.Client.Common/rewind/IRewinder.cs b/src/BizHawk.Client.Common/rewind/IRewinder.cs index 6e88dd6d0e..578ae37f67 100644 --- a/src/BizHawk.Client.Common/rewind/IRewinder.cs +++ b/src/BizHawk.Client.Common/rewind/IRewinder.cs @@ -13,9 +13,9 @@ namespace BizHawk.Client.Common void Capture(int frame); /// - /// Rewind 1 saved frame, if possible + /// Rewind 1 or 2 saved frames, avoiding frameToAvoid if possible. /// - bool Rewind(); + bool Rewind(int frameToAvoid); void Suspend(); void Resume(); diff --git a/src/BizHawk.Client.Common/rewind/Zwinder.cs b/src/BizHawk.Client.Common/rewind/Zwinder.cs index 93d62172bd..dd4e048197 100644 --- a/src/BizHawk.Client.Common/rewind/Zwinder.cs +++ b/src/BizHawk.Client.Common/rewind/Zwinder.cs @@ -60,12 +60,18 @@ namespace BizHawk.Client.Common _buffer.Capture(frame, s => _stateSource.SaveStateBinary(new BinaryWriter(s))); } - public bool Rewind() + public bool Rewind(int frameToAvoid) { if (!Active || Count == 0) return false; var index = Count - 1; var state = _buffer.GetState(index); + if (state.Frame == frameToAvoid && Count > 1) + { + // Do not decrement index again. We will "head" this state and not pop it since it will be advanced past + // without an opportunity to capture. This is a bit hackish. + state = _buffer.GetState(index - 1); + } _stateSource.LoadStateBinary(new BinaryReader(state.GetReadStream())); _buffer.InvalidateEnd(index); return true; diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs index b64e02ede5..9213f4b30e 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.cs @@ -4517,7 +4517,16 @@ namespace BizHawk.Client.EmuHawk if (isRewinding) { - runFrame = Rewinder.Rewind() && Emulator.Frame > 1; + // Try to avoid the previous frame: We want to frame advance right after rewinding so we can give a useful + // framebuffer. + var frameToAvoid = Emulator.Frame - 1; + runFrame = Rewinder.Rewind(frameToAvoid); + if (Emulator.Frame == frameToAvoid) + { + // The rewinder was unable to satisfy our request. Prefer showing a stale framebuffer to + // advancing in a way that essentially no-ops the entire rewind. + runFrame = false; + } if (runFrame && MovieSession.Movie.IsRecording()) {