From 8789827100bd321791a27b0eec184fe4ee02dc9d Mon Sep 17 00:00:00 2001 From: SuuperW Date: Fri, 28 Aug 2020 16:26:45 -0500 Subject: [PATCH] instead of throwing an exception when the buffer is smaller than the state, don't capture the state --- .../movie/tasproj/ZwinderStateManager.cs | 15 ++++++----- .../rewind/ZwinderBuffer.cs | 27 +++++++++++++++---- .../Movie/ZwinderStateManagerTests.cs | 4 +-- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManager.cs b/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManager.cs index ce750aee89..39aaeec908 100644 --- a/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManager.cs +++ b/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManager.cs @@ -281,11 +281,10 @@ namespace BizHawk.Client.Common return; } - _current.Capture(frame, + bool currentCaptured =_current.Capture(frame, s => { source.SaveStateBinary(new BinaryWriter(s)); - StateCache.Add(frame); }, index => { @@ -299,11 +298,10 @@ namespace BizHawk.Client.Common return; } - _recent.Capture(state.Frame, + bool recentCaptured = _recent.Capture(state.Frame, s => { state.GetReadStream().CopyTo(s); - StateCache.Add(state.Frame); }, index2 => { @@ -318,8 +316,12 @@ 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 @@ -356,13 +358,14 @@ namespace BizHawk.Client.Common private void CaptureGap(int frame, IStatable source) { - _gapFiller.Capture( + bool captured = _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 75c2051c11..b1ba257f9b 100644 --- a/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs +++ b/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs @@ -134,15 +134,16 @@ 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 performed + /// will be called with the stream if capture is to be attempted /// - /// 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 /// - public void Capture(int frame, Action callback, Action indexInvalidated = null, bool force = false) + /// Returns true if the state was sucesfully captured; otherwise false. + public bool Capture(int frame, Action callback, Action indexInvalidated = null, bool force = false) { if ((!force && !ShouldCapture(frame)) || _buffer == null) - return; + return false; if (Count == STATEMASK) { @@ -157,7 +158,7 @@ namespace BizHawk.Client.Common Func notifySizeReached = () => { if (Count == 0) - throw new IOException("A single state must not be larger than the buffer"); + return 0; indexInvalidated?.Invoke(0); _firstStateIndex = (_firstStateIndex + 1) & STATEMASK; return Count > 0 @@ -176,12 +177,19 @@ 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) @@ -368,7 +376,16 @@ 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 8683d2c028..68b2145f8c 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++) { - zb.Capture(i, s => ss.SaveStateBinary(new BinaryWriter(s)), j => stateCount--, true); - stateCount++; + if (zb.Capture(i, s => ss.SaveStateBinary(new BinaryWriter(s)), j => stateCount--, true)) + stateCount++; } Assert.AreEqual(zb.Count, stateCount); }