diff --git a/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManager.cs b/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManager.cs
index 39aaeec908..ce750aee89 100644
--- a/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManager.cs
+++ b/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManager.cs
@@ -281,10 +281,11 @@ namespace BizHawk.Client.Common
return;
}
- bool currentCaptured =_current.Capture(frame,
+ _current.Capture(frame,
s =>
{
source.SaveStateBinary(new BinaryWriter(s));
+ StateCache.Add(frame);
},
index =>
{
@@ -298,10 +299,11 @@ namespace BizHawk.Client.Common
return;
}
- bool recentCaptured = _recent.Capture(state.Frame,
+ _recent.Capture(state.Frame,
s =>
{
state.GetReadStream().CopyTo(s);
+ StateCache.Add(state.Frame);
},
index2 =>
{
@@ -316,12 +318,8 @@ namespace BizHawk.Client.Common
AddToReserved(state2);
}
});
- if (recentCaptured)
- StateCache.Add(state.Frame);
},
force);
- if (currentCaptured)
- StateCache.Add(frame);
}
// Returns whether or not a frame has a reserved state within the frame interval on either side of it
@@ -358,14 +356,13 @@ namespace BizHawk.Client.Common
private void CaptureGap(int frame, IStatable source)
{
- bool captured = _gapFiller.Capture(
+ _gapFiller.Capture(
frame, s =>
{
+ StateCache.Add(frame);
source.SaveStateBinary(new BinaryWriter(s));
},
index => StateCache.Remove(index));
- if (captured)
- StateCache.Add(frame);
}
public void Clear()
diff --git a/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs b/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs
index b1ba257f9b..0c8629a5a8 100644
--- a/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs
+++ b/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs
@@ -20,22 +20,23 @@ namespace BizHawk.Client.Common
public ZwinderBuffer(IRewindSettings settings)
{
long targetSize = settings.BufferSize * 1024 * 1024;
+ if (settings.TargetFrameLength < 1)
+ {
+ throw new ArgumentOutOfRangeException(nameof(settings.TargetFrameLength));
+ }
Size = 1L << (int)Math.Floor(Math.Log(targetSize, 2));
_sizeMask = Size - 1;
+ _buffer = new MemoryBlock((ulong)Size);
+ _buffer.Protect(_buffer.Start, _buffer.Size, MemoryBlock.Protection.RW);
_targetFrameLength = settings.TargetFrameLength;
+ _states = new StateInfo[STATEMASK + 1];
_useCompression = settings.UseCompression;
- if (Size > 1)
- {
- _buffer = new MemoryBlock((ulong)Size);
- _buffer.Protect(_buffer.Start, _buffer.Size, MemoryBlock.Protection.RW);
- _states = new StateInfo[STATEMASK + 1];
- }
}
public void Dispose()
{
- _buffer?.Dispose();
+ _buffer.Dispose();
}
@@ -134,16 +135,15 @@ namespace BizHawk.Client.Common
/// Maybe captures a state, if the conditions are favorable
///
/// frame number to capture
- /// will be called with the stream if capture is to be attempted
+ /// will be called with the stream if capture is to be performed
///
- /// If provided, will be called with the index of states that are about to be removed. This will happen during
+ /// If provided, will be called with the index of states that are about to be removed. This will happen during
/// calls to Write() inside `callback`, and any reuse of the old state will have to happen immediately
///
- /// Returns true if the state was sucesfully captured; otherwise false.
- public bool Capture(int frame, Action callback, Action indexInvalidated = null, bool force = false)
+ public void Capture(int frame, Action callback, Action indexInvalidated = null, bool force = false)
{
- if ((!force && !ShouldCapture(frame)) || _buffer == null)
- return false;
+ if (!force && !ShouldCapture(frame))
+ return;
if (Count == STATEMASK)
{
@@ -158,7 +158,7 @@ namespace BizHawk.Client.Common
Func notifySizeReached = () =>
{
if (Count == 0)
- return 0;
+ throw new IOException("A single state must not be larger than the buffer");
indexInvalidated?.Invoke(0);
_firstStateIndex = (_firstStateIndex + 1) & STATEMASK;
return Count > 0
@@ -177,19 +177,12 @@ namespace BizHawk.Client.Common
callback(stream);
}
- if (stream.Length > Size)
- {
- Util.DebugWriteLine("Failed to capture; state size exceeds buffer size.");
- return false;
- }
-
_states[_nextStateIndex].Frame = frame;
_states[_nextStateIndex].Start = start;
_states[_nextStateIndex].Size = (int)stream.Length;
_nextStateIndex = (_nextStateIndex + 1) & STATEMASK;
//Util.DebugWriteLine($"Size: {Size >> 20}MiB, Used: {Used >> 20}MiB, States: {Count}");
- return true;
}
private Stream MakeLoadStream(int index)
@@ -293,11 +286,8 @@ namespace BizHawk.Client.Common
nextByte += _states[i].Size;
}
// TODO: Use spans to avoid this extra copy in .net core
- if (nextByte > 0)
- {
- var dest = _buffer.GetStream(_buffer.Start, (ulong)nextByte, true);
- WaterboxUtils.CopySome(reader.BaseStream, dest, nextByte);
- }
+ var dest = _buffer.GetStream(_buffer.Start, (ulong)nextByte, true);
+ WaterboxUtils.CopySome(reader.BaseStream, dest, nextByte);
}
public static ZwinderBuffer Create(BinaryReader reader)
@@ -376,16 +366,7 @@ namespace BizHawk.Client.Common
{
long requestedSize = _position + buffer.Length;
while (requestedSize > _notifySize)
- {
_notifySize = _notifySizeReached();
- // 0 means abort, because the buffer is too small
- if (_notifySize == 0)
- {
- // we set _position so that we can check later if the attempted write length was larger than the available buffer size
- _position += buffer.Length;
- return;
- }
- }
long n = buffer.Length;
if (n > 0)
{
diff --git a/src/BizHawk.Tests/Client.Common/Movie/ZwinderStateManagerTests.cs b/src/BizHawk.Tests/Client.Common/Movie/ZwinderStateManagerTests.cs
index 68b2145f8c..8683d2c028 100644
--- a/src/BizHawk.Tests/Client.Common/Movie/ZwinderStateManagerTests.cs
+++ b/src/BizHawk.Tests/Client.Common/Movie/ZwinderStateManagerTests.cs
@@ -71,8 +71,8 @@ namespace BizHawk.Tests.Client.Common.Movie
var stateCount = 0;
for (int i = 0; i < 1000000; i++)
{
- if (zb.Capture(i, s => ss.SaveStateBinary(new BinaryWriter(s)), j => stateCount--, true))
- stateCount++;
+ zb.Capture(i, s => ss.SaveStateBinary(new BinaryWriter(s)), j => stateCount--, true);
+ stateCount++;
}
Assert.AreEqual(zb.Count, stateCount);
}