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

@ -5,13 +5,13 @@
/// <summary>
/// Gets a value indicating whether or not to compress savestates before storing them
/// </summary>
bool UseCompression { get; }
bool UseCompression { get; }
/// <summary>
/// Gets a value indicating whether or not to delta compress savestates before storing them
/// </summary>
/// <value></value>
// TODO: This is in here for frontend reasons, but the buffer itself doesn't interact with this.
// TODO: This is in here for frontend reasons, but the buffer itself doesn't interact with this.
bool UseDelta { get; }
/// <summary>
@ -53,6 +53,7 @@
public bool UseCompression { get; set; } = false;
public bool UseDelta { get; set; } = false;
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 bool UseFixedRewindInterval { get; set; } = false;
public int TargetFrameLength { get; set; } = 600;

View File

@ -196,7 +196,7 @@ namespace BizHawk.Client.Common
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")
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;
}
// avoid capturing in this case
if (source.AvoidRewind)
{
return;
}
_current.Capture(frame,
s =>
{
@ -372,8 +378,7 @@ namespace BizHawk.Client.Common
AddToReserved(state2);
}
});
},
force);
});
}
// 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()
{
Rewinder?.Dispose();
Rewinder = Emulator.HasSavestates() && Config.Rewind.Enabled
Rewinder = Emulator.HasSavestates() && Config.Rewind.Enabled && (!Emulator.AsStatable().AvoidRewind || Config.Rewind.AllowSlowStates)
? Config.Rewind.UseDelta
? new ZeldaWinder(Emulator.AsStatable(), Config.Rewind)
: new Zwinder(Emulator.AsStatable(), Config.Rewind)

View File

@ -174,16 +174,40 @@ namespace BizHawk.Client.EmuHawk
public TasBranch SelectedBranch
=> 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()
{
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,
CoreData = Tastudio.StatableEmulator.CloneSavestate(),
CoreData = bufferedStatable.BufferedState,
InputLog = Movie.GetLogEntries().Clone(),
CoreFrameBuffer = MainForm.MakeScreenshotImage(),
OSDFrameBuffer = MainForm.CaptureOSD(),
ChangeLog = new TasMovieChangeLog(Movie),
ChangeLog = new(Movie),
TimeStamp = DateTime.Now,
Markers = Movie.Markers.DeepClone(),
UserText = Movie.Branches.NewBranchText
@ -199,8 +223,8 @@ namespace BizHawk.Client.EmuHawk
}
Movie.LoadBranch(branch);
Tastudio.LoadState(new KeyValuePair<int, Stream>(branch.Frame, new MemoryStream(branch.CoreData, false)));
Movie.TasStateManager.Capture(Tastudio.Emulator.Frame, Tastudio.Emulator.AsStatable());
Tastudio.LoadState(new(branch.Frame, new MemoryStream(branch.CoreData, false)));
Movie.TasStateManager.Capture(Tastudio.Emulator.Frame, Tastudio.Emulator.AsStatable(), Tastudio.Emulator.AsStatable().AvoidRewind);
Tastudio.MainForm.QuickBmpFile.Copy(new BitmapBufferVideoProvider(branch.CoreFrameBuffer), Tastudio.VideoProvider);
if (Tastudio.Settings.OldControlSchemeForBranches && Tastudio.TasPlaybackBox.RecordingMode)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -151,6 +151,9 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.N3DS
}
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();
}

View File

@ -294,6 +294,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES
// private int serializedSize;
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer)
{
// 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 bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer)
{
Api.SaveStateBinary(writer);

View File

@ -9,6 +9,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
{
private byte[] _savebuff = Array.Empty<byte>();
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter writer)
{
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 _rStates;
public bool AvoidRewind => _lStates.AvoidRewind || _rStates.AvoidRewind;
public void SaveStateBinary(BinaryWriter bw)
{
_lStates.SaveStateBinary(bw);

View File

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

View File

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

View File

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

View File

@ -9,6 +9,20 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
{
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)
{
ser.Serialize(writer, new GBLSerialized(this));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -342,6 +342,8 @@ namespace BizHawk.Emulation.Cores.Waterbox
}
}
public bool AvoidRewind => false;
public void SaveStateBinary(BinaryWriter bw)
{
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 byte[] PaddingData { get; set; } = Array.Empty<byte>();
public bool AvoidRewind => false;
public void LoadStateBinary(BinaryReader reader)
{
Frame = reader.ReadInt32();