Add in flag to IStatable to hint to the frontend that it should avoid rewind (not entire sure with the name, maybe SlowStates would have been better? trivial to mass-rename anyways)

Add in logic to not create the main rewinder if this flag is true, and add in logic to tastudio to avoid the main greenzone captures (instead only capture on branch save/load)
This commit is contained in:
CasualPokePlayer 2023-07-28 22:07:31 -07:00
parent 1ad3ed2216
commit 12830bab4e
37 changed files with 119 additions and 12 deletions

View File

@ -53,6 +53,7 @@
public bool UseCompression { get; set; } = false; public bool UseCompression { get; set; } = false;
public bool UseDelta { get; set; } = false; public bool UseDelta { get; set; } = false;
public bool Enabled { get; set; } = true; public bool Enabled { get; set; } = true;
public bool AllowSlowStates { get; set; } = false; // TODO: Hook up in UI
public long BufferSize { get; set; } = 512; // in mb public long BufferSize { get; set; } = 512; // in mb
public bool UseFixedRewindInterval { get; set; } = false; public bool UseFixedRewindInterval { get; set; } = false;
public int TargetFrameLength { get; set; } = 600; public int TargetFrameLength { get; set; } = 600;

View File

@ -196,7 +196,7 @@ namespace BizHawk.Client.Common
LagLog[Emulator.Frame] = _inputPollable.IsLagFrame; LagLog[Emulator.Frame] = _inputPollable.IsLagFrame;
// We will forbibly capture a state for the last edited frame (requested by #916 for case of "platforms with analog stick") // We will forbibly capture a state for the last edited frame (requested by #916 for case of "platforms with analog stick")
TasStateManager.Capture(Emulator.Frame, Emulator.AsStatable(), Emulator.Frame == LastEditedFrame - 1); TasStateManager.Capture(Emulator.Frame, Emulator.AsStatable(), !Emulator.AsStatable().AvoidRewind && Emulator.Frame == LastEditedFrame - 1);
} }

View File

@ -334,6 +334,12 @@ namespace BizHawk.Client.Common
return; return;
} }
// avoid capturing in this case
if (source.AvoidRewind)
{
return;
}
_current.Capture(frame, _current.Capture(frame,
s => s =>
{ {
@ -372,8 +378,7 @@ namespace BizHawk.Client.Common
AddToReserved(state2); AddToReserved(state2);
} }
}); });
}, });
force);
} }
// Returns whether or not a frame has a reserved state within the frame interval on either side of it // Returns whether or not a frame has a reserved state within the frame interval on either side of it

View File

@ -1064,7 +1064,7 @@ namespace BizHawk.Client.EmuHawk
public void CreateRewinder() public void CreateRewinder()
{ {
Rewinder?.Dispose(); Rewinder?.Dispose();
Rewinder = Emulator.HasSavestates() && Config.Rewind.Enabled Rewinder = Emulator.HasSavestates() && Config.Rewind.Enabled && (!Emulator.AsStatable().AvoidRewind || Config.Rewind.AllowSlowStates)
? Config.Rewind.UseDelta ? Config.Rewind.UseDelta
? new ZeldaWinder(Emulator.AsStatable(), Config.Rewind) ? new ZeldaWinder(Emulator.AsStatable(), Config.Rewind)
: new Zwinder(Emulator.AsStatable(), Config.Rewind) : new Zwinder(Emulator.AsStatable(), Config.Rewind)

View File

@ -174,16 +174,40 @@ namespace BizHawk.Client.EmuHawk
public TasBranch SelectedBranch public TasBranch SelectedBranch
=> BranchView.AnyRowsSelected ? Branches[BranchView.FirstSelectedRowIndex] : null; => BranchView.AnyRowsSelected ? Branches[BranchView.FirstSelectedRowIndex] : null;
// to avoid a double (potentially slow) state
private class BufferedStatable : IStatable
{
private readonly Lazy<byte[]> _bufferedState;
public byte[] BufferedState => _bufferedState.Value;
public BufferedStatable(IStatable statable)
{
_bufferedState = new(statable.CloneSavestate);
AvoidRewind = statable.AvoidRewind;
}
public bool AvoidRewind { get; }
public void SaveStateBinary(BinaryWriter writer)
=> writer.Write(BufferedState);
public void LoadStateBinary(BinaryReader reader)
=> throw new NotImplementedException();
}
private TasBranch CreateBranch() private TasBranch CreateBranch()
{ {
return new TasBranch var bufferedStatable = new BufferedStatable(Tastudio.Emulator.AsStatable());
Movie.TasStateManager.Capture(Tastudio.Emulator.Frame, bufferedStatable, bufferedStatable.AvoidRewind);
return new()
{ {
Frame = Tastudio.Emulator.Frame, Frame = Tastudio.Emulator.Frame,
CoreData = Tastudio.StatableEmulator.CloneSavestate(), CoreData = bufferedStatable.BufferedState,
InputLog = Movie.GetLogEntries().Clone(), InputLog = Movie.GetLogEntries().Clone(),
CoreFrameBuffer = MainForm.MakeScreenshotImage(), CoreFrameBuffer = MainForm.MakeScreenshotImage(),
OSDFrameBuffer = MainForm.CaptureOSD(), OSDFrameBuffer = MainForm.CaptureOSD(),
ChangeLog = new TasMovieChangeLog(Movie), ChangeLog = new(Movie),
TimeStamp = DateTime.Now, TimeStamp = DateTime.Now,
Markers = Movie.Markers.DeepClone(), Markers = Movie.Markers.DeepClone(),
UserText = Movie.Branches.NewBranchText UserText = Movie.Branches.NewBranchText
@ -199,8 +223,8 @@ namespace BizHawk.Client.EmuHawk
} }
Movie.LoadBranch(branch); Movie.LoadBranch(branch);
Tastudio.LoadState(new KeyValuePair<int, Stream>(branch.Frame, new MemoryStream(branch.CoreData, false))); Tastudio.LoadState(new(branch.Frame, new MemoryStream(branch.CoreData, false)));
Movie.TasStateManager.Capture(Tastudio.Emulator.Frame, Tastudio.Emulator.AsStatable()); Movie.TasStateManager.Capture(Tastudio.Emulator.Frame, Tastudio.Emulator.AsStatable(), Tastudio.Emulator.AsStatable().AvoidRewind);
Tastudio.MainForm.QuickBmpFile.Copy(new BitmapBufferVideoProvider(branch.CoreFrameBuffer), Tastudio.VideoProvider); Tastudio.MainForm.QuickBmpFile.Copy(new BitmapBufferVideoProvider(branch.CoreFrameBuffer), Tastudio.VideoProvider);
if (Tastudio.Settings.OldControlSchemeForBranches && Tastudio.TasPlaybackBox.RecordingMode) if (Tastudio.Settings.OldControlSchemeForBranches && Tastudio.TasPlaybackBox.RecordingMode)

View File

@ -28,6 +28,8 @@ namespace BizHawk.Emulation.Common
/// </summary> /// </summary>
public Action LoadStateCallback { get; set; } public Action LoadStateCallback { get; set; }
public bool AvoidRewind => false;
public void SaveStateText(TextWriter writer) public void SaveStateText(TextWriter writer)
{ {
_syncState(Serializer.CreateTextWriter(writer)); _syncState(Serializer.CreateTextWriter(writer));

View File

@ -13,6 +13,7 @@ namespace BizHawk.Emulation.Common
/// </summary> /// </summary>
public interface IStatable : IEmulatorService public interface IStatable : IEmulatorService
{ {
bool AvoidRewind { get; }
void SaveStateBinary(BinaryWriter writer); void SaveStateBinary(BinaryWriter writer);
void LoadStateBinary(BinaryReader reader); void LoadStateBinary(BinaryReader reader);
} }

View File

@ -7,6 +7,8 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME
{ {
public partial class MAME : IStatable public partial class MAME : IStatable
{ {
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
using (_exe.EnterExit()) using (_exe.EnterExit())

View File

@ -9,6 +9,8 @@ namespace BizHawk.Emulation.Cores.Calculators.Emu83
{ {
private readonly byte[] _stateBuf = new byte[LibEmu83.TI83_GetStateSize()]; private readonly byte[] _stateBuf = new byte[LibEmu83.TI83_GetStateSize()];
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
if (!LibEmu83.TI83_SaveState(Context, _stateBuf)) if (!LibEmu83.TI83_SaveState(Context, _stateBuf))

View File

@ -7,6 +7,8 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII
{ {
public partial class AppleII : ITextStatable public partial class AppleII : ITextStatable
{ {
public bool AvoidRewind => false;
public void SaveStateText(TextWriter writer) public void SaveStateText(TextWriter writer)
{ {
SyncState(new AppleSerializer(writer)); SyncState(new AppleSerializer(writer));

View File

@ -8,6 +8,8 @@ namespace BizHawk.Emulation.Cores.Atari.Lynx
{ {
public partial class Lynx : ITextStatable public partial class Lynx : ITextStatable
{ {
public bool AvoidRewind => false;
public void SaveStateText(TextWriter writer) public void SaveStateText(TextWriter writer)
{ {
var s = new TextState<TextStateData>(); var s = new TextState<TextStateData>();

View File

@ -9,6 +9,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.N3DS
{ {
private byte[] _stateBuf = Array.Empty<byte>(); private byte[] _stateBuf = Array.Empty<byte>();
public bool AvoidRewind => true;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
var stateLen = _core.Citra_StartSaveState(_context); var stateLen = _core.Citra_StartSaveState(_context);

View File

@ -151,6 +151,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.N3DS
} }
InitMemoryDomains(); InitMemoryDomains();
// for some reason, if a savestate is created on frame 0, Citra will crash if another savestate is made after loading that state
// advance one frame to avoid that issue
_core.Citra_RunFrame(_context);
OnVideoRefresh(); OnVideoRefresh();
} }

View File

@ -294,6 +294,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
// private int serializedSize; // private int serializedSize;
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
// commented code left for debug purposes; created savestates are native bsnes savestates // commented code left for debug purposes; created savestates are native bsnes savestates

View File

@ -5,6 +5,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
{ {
public partial class BsnesCore : IStatable public partial class BsnesCore : IStatable
{ {
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
Api.SaveStateBinary(writer); Api.SaveStateBinary(writer);

View File

@ -9,6 +9,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
{ {
private byte[] _savebuff = Array.Empty<byte>(); private byte[] _savebuff = Array.Empty<byte>();
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
if (!LibmGBA.BizStartGetState(Core, out var p, out var size)) if (!LibmGBA.BizStartGetState(Core, out var p, out var size))

View File

@ -10,6 +10,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink
private readonly IStatable _lStates; private readonly IStatable _lStates;
private readonly IStatable _rStates; private readonly IStatable _rStates;
public bool AvoidRewind => _lStates.AvoidRewind || _rStates.AvoidRewind;
public void SaveStateBinary(BinaryWriter bw) public void SaveStateBinary(BinaryWriter bw)
{ {
_lStates.SaveStateBinary(bw); _lStates.SaveStateBinary(bw);

View File

@ -10,6 +10,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x
private readonly IStatable _cStates; private readonly IStatable _cStates;
private readonly IStatable _rStates; private readonly IStatable _rStates;
public bool AvoidRewind => _lStates.AvoidRewind || _cStates.AvoidRewind || _rStates.AvoidRewind;
public void SaveStateBinary(BinaryWriter bw) public void SaveStateBinary(BinaryWriter bw)
{ {
_lStates.SaveStateBinary(bw); _lStates.SaveStateBinary(bw);

View File

@ -12,6 +12,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink4x
private readonly IStatable _cStates; private readonly IStatable _cStates;
private readonly IStatable _dStates; private readonly IStatable _dStates;
public bool AvoidRewind => _aStates.AvoidRewind || _bStates.AvoidRewind || _cStates.AvoidRewind || _dStates.AvoidRewind;
public void SaveStateBinary(BinaryWriter bw) public void SaveStateBinary(BinaryWriter bw)
{ {
_aStates.SaveStateBinary(bw); _aStates.SaveStateBinary(bw);

View File

@ -11,6 +11,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{ {
public partial class Gameboy : IStatable, ITextStatable public partial class Gameboy : IStatable, ITextStatable
{ {
public bool AvoidRewind => false;
public void SaveStateText(TextWriter writer) public void SaveStateText(TextWriter writer)
{ {
var s = SaveState(); var s = SaveState();

View File

@ -9,6 +9,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{ {
public partial class GambatteLink : ITextStatable public partial class GambatteLink : ITextStatable
{ {
public bool AvoidRewind
{
get
{
var ret = false;
for (var i = 0; i < _numCores; i++)
{
ret |= _linkedCores[i].AvoidRewind;
}
return ret;
}
}
public void SaveStateText(TextWriter writer) public void SaveStateText(TextWriter writer)
{ {
ser.Serialize(writer, new GBLSerialized(this)); ser.Serialize(writer, new GBLSerialized(this));

View File

@ -8,6 +8,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
{ {
public partial class N64 : IStatable public partial class N64 : IStatable
{ {
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
byte[] data = SaveStatePrivateBuff; byte[] data = SaveStatePrivateBuff;

View File

@ -6,6 +6,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
{ {
public partial class QuickNES : IStatable public partial class QuickNES : IStatable
{ {
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
CheckDisposed(); CheckDisposed();

View File

@ -428,6 +428,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
_readonlyFiles.Clear(); _readonlyFiles.Clear();
} }
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
_exe.SaveStateBinary(writer); _exe.SaveStateBinary(writer);

View File

@ -5,6 +5,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
{ {
public partial class LibsnesCore : IStatable public partial class LibsnesCore : IStatable
{ {
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
Api.SaveStateBinary(writer); Api.SaveStateBinary(writer);

View File

@ -9,6 +9,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
{ {
private readonly byte[] _stateBuf; private readonly byte[] _stateBuf;
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
LibSameboy.sameboy_savestate(SameboyState, _stateBuf); LibSameboy.sameboy_savestate(SameboyState, _stateBuf);

View File

@ -9,6 +9,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubGBHawk
{ {
private readonly IStatable _GBStatable; private readonly IStatable _GBStatable;
public bool AvoidRewind => _GBStatable.AvoidRewind;
public void SaveStateBinary(BinaryWriter bw) public void SaveStateBinary(BinaryWriter bw)
{ {
_GBStatable.SaveStateBinary(bw); _GBStatable.SaveStateBinary(bw);

View File

@ -9,6 +9,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.SubNESHawk
{ {
private readonly IStatable _nesStatable; private readonly IStatable _nesStatable;
public bool AvoidRewind => _nesStatable.AvoidRewind;
public void SaveStateBinary(BinaryWriter bw) public void SaveStateBinary(BinaryWriter bw)
{ {
_nesStatable.SaveStateBinary(bw); _nesStatable.SaveStateBinary(bw);

View File

@ -10,6 +10,8 @@ namespace BizHawk.Emulation.Cores.Sega.GGHawkLink
private readonly IStatable _lStates; private readonly IStatable _lStates;
private readonly IStatable _rStates; private readonly IStatable _rStates;
public bool AvoidRewind => _lStates.AvoidRewind || _rStates.AvoidRewind;
public void SaveStateBinary(BinaryWriter bw) public void SaveStateBinary(BinaryWriter bw)
{ {
_lStates.SaveStateBinary(bw); _lStates.SaveStateBinary(bw);

View File

@ -5,6 +5,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
{ {
public partial class GPGX : IStatable public partial class GPGX : IStatable
{ {
public bool AvoidRewind => false;
public void LoadStateBinary(BinaryReader reader) public void LoadStateBinary(BinaryReader reader)
{ {
_elf.LoadStateBinary(reader); _elf.LoadStateBinary(reader);

View File

@ -1038,6 +1038,8 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
savebuff = new byte[size]; savebuff = new byte[size];
} }
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
fixed (byte* psavebuff = savebuff) fixed (byte* psavebuff = savebuff)

View File

@ -59,6 +59,8 @@ namespace BizHawk.Emulation.Cores.WonderSwan
private byte[] savebuff; private byte[] savebuff;
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
if (!BizSwan.bizswan_binstatesave(Core, savebuff, savebuff.Length)) if (!BizSwan.bizswan_binstatesave(Core, savebuff, savebuff.Length))

View File

@ -21,6 +21,8 @@ namespace BizHawk.Emulation.Cores.Libretro
_stateBuf = new byte[maxSize]; _stateBuf = new byte[maxSize];
} }
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
var len = checked((int)_api.retro_serialize_size()); var len = checked((int)_api.retro_serialize_size());

View File

@ -328,6 +328,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
private const ulong MAGIC = 9569546739673486731; private const ulong MAGIC = 9569546739673486731;
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer) public void SaveStateBinary(BinaryWriter writer)
{ {
writer.Write(MAGIC); writer.Write(MAGIC);

View File

@ -263,6 +263,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem(); public IInputCallbackSystem InputCallbacks { get; } = new InputCallbackSystem();
public virtual ControllerDefinition ControllerDefinition { get; protected set; } = NullController.Instance.Definition; public virtual ControllerDefinition ControllerDefinition { get; protected set; } = NullController.Instance.Definition;
public bool AvoidRewind => false;
public void LoadStateBinary(BinaryReader reader) public void LoadStateBinary(BinaryReader reader)
{ {
using (_exe.EnterExit()) using (_exe.EnterExit())

View File

@ -342,6 +342,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
} }
} }
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter bw) public void SaveStateBinary(BinaryWriter bw)
{ {
using var writer = new ReadWriteWrapper(bw.BaseStream, false); using var writer = new ReadWriteWrapper(bw.BaseStream, false);

View File

@ -575,6 +575,9 @@ namespace BizHawk.Tests.Client.Common.Movie
{ {
public int Frame { get; set; } public int Frame { get; set; }
public byte[] PaddingData { get; set; } = Array.Empty<byte>(); public byte[] PaddingData { get; set; } = Array.Empty<byte>();
public bool AvoidRewind => false;
public void LoadStateBinary(BinaryReader reader) public void LoadStateBinary(BinaryReader reader)
{ {
Frame = reader.ReadInt32(); Frame = reader.ReadInt32();