Rewind: Fix subtle off-by-one-frame bugs (only really noticeable when frame advancing).
This commit is contained in:
parent
e767e1b673
commit
3f776dbf6f
|
@ -15,6 +15,7 @@ namespace BizHawk.Client.Common
|
||||||
private byte[] _lastState;
|
private byte[] _lastState;
|
||||||
private int _rewindFrequency = 1;
|
private int _rewindFrequency = 1;
|
||||||
private bool _rewindDeltaEnable;
|
private bool _rewindDeltaEnable;
|
||||||
|
private bool _lastRewindLoadedState;
|
||||||
private byte[] _deltaBuffer = new byte[0];
|
private byte[] _deltaBuffer = new byte[0];
|
||||||
|
|
||||||
public Rewinder()
|
public Rewinder()
|
||||||
|
@ -41,11 +42,6 @@ namespace BizHawk.Client.Common
|
||||||
get { return _rewindBuffer != null ? _rewindBuffer.Size : 0; }
|
get { return _rewindBuffer != null ? _rewindBuffer.Size : 0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public int BufferCount
|
|
||||||
{
|
|
||||||
get { return _rewindBuffer != null ? _rewindBuffer.Count : 0; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool HasBuffer
|
public bool HasBuffer
|
||||||
{
|
{
|
||||||
get { return _rewindBuffer != null; }
|
get { return _rewindBuffer != null; }
|
||||||
|
@ -125,26 +121,31 @@ namespace BizHawk.Client.Common
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Rewind(int frames)
|
public bool Rewind(int frames)
|
||||||
{
|
{
|
||||||
if (!Global.Emulator.HasSavestates() || _rewindThread == null)
|
if (!Global.Emulator.HasSavestates() || _rewindThread == null)
|
||||||
{
|
{
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
_rewindThread.Rewind(frames);
|
_rewindThread.Rewind(frames);
|
||||||
|
|
||||||
|
return _lastRewindLoadedState;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RewindInternal(int frames)
|
private void RewindInternal(int frames)
|
||||||
{
|
{
|
||||||
|
_lastRewindLoadedState = false;
|
||||||
|
|
||||||
for (int i = 0; i < frames; i++)
|
for (int i = 0; i < frames; i++)
|
||||||
{
|
{
|
||||||
if (_rewindBuffer.Count == 0 || (Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.InputLogLength == 0))
|
if (_rewindBuffer.Count <= 1 || (Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.InputLogLength == 0))
|
||||||
{
|
{
|
||||||
return;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadPreviousState();
|
LoadPreviousState();
|
||||||
|
_lastRewindLoadedState = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,19 +352,27 @@ namespace BizHawk.Client.Common
|
||||||
UpdateLastState(currentState);
|
UpdateLastState(currentState);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadPreviousState()
|
private MemoryStream GetPreviousStateMemoryStream()
|
||||||
{
|
{
|
||||||
using (var reader = new BinaryReader(_rewindBuffer.PopMemoryStream()))
|
|
||||||
{
|
|
||||||
byte[] buf = ((MemoryStream)reader.BaseStream).GetBuffer();
|
|
||||||
var fullState = reader.ReadByte() == 1;
|
|
||||||
if (_rewindDeltaEnable)
|
if (_rewindDeltaEnable)
|
||||||
{
|
{
|
||||||
using (var lastStateReader = new BinaryReader(new MemoryStream(_lastState)))
|
return _rewindBuffer.PopMemoryStream();
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Global.Emulator.AsStatable().LoadStateBinary(lastStateReader);
|
_rewindBuffer.Pop();
|
||||||
|
return _rewindBuffer.PeekMemoryStream();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void LoadPreviousState()
|
||||||
|
{
|
||||||
|
using (var reader = new BinaryReader(GetPreviousStateMemoryStream()))
|
||||||
|
{
|
||||||
|
byte[] buf = ((MemoryStream)reader.BaseStream).GetBuffer();
|
||||||
|
bool fullState = reader.ReadByte() == 1;
|
||||||
|
if (_rewindDeltaEnable)
|
||||||
|
{
|
||||||
if (fullState)
|
if (fullState)
|
||||||
{
|
{
|
||||||
UpdateLastState(buf, 1, buf.Length - 1);
|
UpdateLastState(buf, 1, buf.Length - 1);
|
||||||
|
@ -384,6 +393,11 @@ namespace BizHawk.Client.Common
|
||||||
index += length;
|
index += length;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
using (var lastStateReader = new BinaryReader(new MemoryStream(_lastState)))
|
||||||
|
{
|
||||||
|
Global.Emulator.AsStatable().LoadStateBinary(lastStateReader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -95,12 +95,20 @@ namespace BizHawk.Client.Common
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public MemoryStream PopMemoryStream()
|
public MemoryStream PopMemoryStream()
|
||||||
{
|
{
|
||||||
var item = Pop();
|
return CreateMemoryStream(Pop());
|
||||||
|
}
|
||||||
|
|
||||||
|
public MemoryStream PeekMemoryStream()
|
||||||
|
{
|
||||||
|
return CreateMemoryStream(Peek());
|
||||||
|
}
|
||||||
|
|
||||||
|
private MemoryStream CreateMemoryStream(ListItem item)
|
||||||
|
{
|
||||||
var buf = new byte[item.Length];
|
var buf = new byte[item.Length];
|
||||||
_mStream.Position = item.Index;
|
_mStream.Position = item.Index;
|
||||||
_mStream.Read(buf, 0, item.Length);
|
_mStream.Read(buf, 0, item.Length);
|
||||||
var ret = new MemoryStream(buf, 0, item.Length, false, true);
|
return new MemoryStream(buf, 0, item.Length, false, true);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public long Enqueue(int timestamp, int amount)
|
public long Enqueue(int timestamp, int amount)
|
||||||
|
@ -199,6 +207,16 @@ namespace BizHawk.Client.Common
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ListItem Peek()
|
||||||
|
{
|
||||||
|
if (_mHead == null)
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException("Attempted to peek from an empty data structure");
|
||||||
|
}
|
||||||
|
|
||||||
|
return _mHead.Value;
|
||||||
|
}
|
||||||
|
|
||||||
public ListItem Dequeue()
|
public ListItem Dequeue()
|
||||||
{
|
{
|
||||||
if (_mTail == null)
|
if (_mTail == null)
|
||||||
|
|
|
@ -4186,8 +4186,7 @@ namespace BizHawk.Client.EmuHawk
|
||||||
|
|
||||||
if (isRewinding)
|
if (isRewinding)
|
||||||
{
|
{
|
||||||
Global.Rewinder.Rewind(1);
|
runFrame = Global.Rewinder.Rewind(1);
|
||||||
runFrame = Global.Rewinder.Count != 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
|
Loading…
Reference in New Issue