diff --git a/src/BizHawk.Client.Common/config/RewindConfig.cs b/src/BizHawk.Client.Common/config/RewindConfig.cs index a4a8ba157f..76040fc0b6 100644 --- a/src/BizHawk.Client.Common/config/RewindConfig.cs +++ b/src/BizHawk.Client.Common/config/RewindConfig.cs @@ -34,6 +34,11 @@ /// int TargetRewindInterval { get; } + /// + /// Specifies if the rewinder should accept states that are given out of order. + /// + bool AllowOutOfOrderStates { get; } + public enum BackingStoreType { Memory, @@ -52,6 +57,8 @@ public bool UseFixedRewindInterval { get; set; } = false; public int TargetFrameLength { get; set; } = 600; public int TargetRewindInterval { get; set; } = 5; + public bool AllowOutOfOrderStates { get; set; } = true; + public IRewindSettings.BackingStoreType BackingStore { get; set; } = IRewindSettings.BackingStoreType.Memory; } } diff --git a/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManager.cs b/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManager.cs index 9875f8067d..29652d4ce4 100644 --- a/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManager.cs +++ b/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManager.cs @@ -320,23 +320,12 @@ namespace BizHawk.Client.Common } // We use the gap buffer for forced capture to avoid crowding the "current" buffer and thus reducing it's actual span of covered frames. - if (force) + if (NeedsGap(frame) || force) { CaptureGap(frame, source); return; } - // We do not want to consider reserved states for a notion of Last - // reserved states can include future states in the case of branch states - if (frame <= LastRing) - { - if (NeedsGap(frame)) - { - CaptureGap(frame, source); - } - return; - } - _current.Capture(frame, s => { @@ -404,6 +393,12 @@ namespace BizHawk.Client.Common private bool NeedsGap(int frame) { + // We don't want to "fill gaps" if we are past the latest state in the current/recent buffers. + if (frame >= LastRing) + { + return false; + } + // When starting to fill gaps we won't actually know the true frequency, so fall back to current // Current may very well not be the same as gap, but it's a reasonable behavior to have a current sized gap before seeing filler sized gaps var frequency = _gapFiller.Count == 0 ? _current.RewindFrequency : _gapFiller.RewindFrequency; diff --git a/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManagerSettings.cs b/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManagerSettings.cs index 25184b24a3..ac4649875e 100644 --- a/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManagerSettings.cs +++ b/src/BizHawk.Client.Common/movie/tasproj/ZwinderStateManagerSettings.cs @@ -109,6 +109,7 @@ namespace BizHawk.Client.Common BufferSize = CurrentBufferSize, UseFixedRewindInterval = false, TargetFrameLength = CurrentTargetFrameLength, + AllowOutOfOrderStates = false, BackingStore = CurrentStoreType }; } @@ -120,6 +121,7 @@ namespace BizHawk.Client.Common BufferSize = RecentBufferSize, UseFixedRewindInterval = false, TargetFrameLength = RecentTargetFrameLength, + AllowOutOfOrderStates = false, BackingStore = RecentStoreType }; } @@ -131,6 +133,7 @@ namespace BizHawk.Client.Common BufferSize = GapsBufferSize, UseFixedRewindInterval = false, TargetFrameLength = GapsTargetFrameLength, + AllowOutOfOrderStates = false, BackingStore = GapsStoreType }; } diff --git a/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs b/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs index 20033138be..e9965418ad 100644 --- a/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs +++ b/src/BizHawk.Client.Common/rewind/ZwinderBuffer.cs @@ -65,6 +65,7 @@ namespace BizHawk.Client.Common _fixedRewindInterval = false; _targetFrameLength = settings.TargetFrameLength; } + _allowOutOfOrderStates = settings.AllowOutOfOrderStates; _states = new StateInfo[STATEMASK + 1]; _useCompression = settings.UseCompression; } @@ -111,6 +112,8 @@ namespace BizHawk.Client.Common private readonly int _targetFrameLength; private readonly int _targetRewindInterval; + private readonly bool _allowOutOfOrderStates; + private struct StateInfo { public long Start; @@ -162,6 +165,7 @@ namespace BizHawk.Client.Common _useCompression == settings.UseCompression && _fixedRewindInterval == settings.UseFixedRewindInterval && (_fixedRewindInterval ? _targetRewindInterval == settings.TargetRewindInterval : _targetFrameLength == settings.TargetFrameLength) && + _allowOutOfOrderStates == settings.AllowOutOfOrderStates && _backingStoreType == settings.BackingStore; } @@ -173,9 +177,8 @@ namespace BizHawk.Client.Common } if (frameDiff < 1) { - // non-linear time is from a combination of other state changing mechanisms and the rewinder - // not much we can say here, so just take a state - return true; + // Manually loading a savestate can cause this. The default rewinder should capture in this situation. + return _allowOutOfOrderStates; } return frameDiff >= ComputeIdealRewindInterval(); } @@ -369,6 +372,7 @@ namespace BizHawk.Client.Common UseFixedRewindInterval = false, TargetFrameLength = targetFrameLength, TargetRewindInterval = 5, + AllowOutOfOrderStates = false, UseCompression = useCompression }); if (ret.Size != size || ret._sizeMask != sizeMask)