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.
This commit is contained in:
nattthebear 2021-03-20 12:05:19 -04:00 committed by GitHub
parent 359cb0d17b
commit 62ddd6495e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 19 additions and 4 deletions

View File

@ -13,9 +13,9 @@ namespace BizHawk.Client.Common
void Capture(int frame);
/// <summary>
/// Rewind 1 saved frame, if possible
/// Rewind 1 or 2 saved frames, avoiding frameToAvoid if possible.
/// </summary>
bool Rewind();
bool Rewind(int frameToAvoid);
void Suspend();
void Resume();

View File

@ -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;

View File

@ -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())
{