From 62ddd6495e653a52b475895ab4769badb2b5c0af Mon Sep 17 00:00:00 2001 From: nattthebear Date: Sat, 20 Mar 2021 12:05:19 -0400 Subject: [PATCH] Tweak the rewinder. (#2668) MainForm intentionally frame advances right after rewinding; this is so it can capture a new framebuffer. The old rewinder sort-of understood this, the new one does not. Tweak the logic so the new rewinder behaves like the old one, but only when the interval is 1. When the interval is greater than 1, don't go farther back than we have to. No particular behavior is guaranteed when nonlinear time exists (ie, rewinding through manual loadstates). Fixes #2667. --- src/BizHawk.Client.Common/rewind/IRewinder.cs | 4 ++-- src/BizHawk.Client.Common/rewind/Zwinder.cs | 8 +++++++- src/BizHawk.Client.EmuHawk/MainForm.cs | 11 ++++++++++- 3 files changed, 19 insertions(+), 4 deletions(-) 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()) {