Break off savestate functionality from IEmulator into IStatable and refactor things accordingly. Still todo (a big todo): EmuHawk should gracefully handle a core that is not an IStatable by disabling functionality dependent upon it (Savestates, Rewind, Tastudio, etc)

This commit is contained in:
adelikat 2014-11-30 16:42:58 +00:00
parent 230cd3fb6a
commit 76148ae111
35 changed files with 200 additions and 242 deletions

View File

@ -1,9 +1,10 @@
using System; using System;
using System.IO; using System.IO;
using BizHawk.Common;
using BizHawk.Common.BufferExtensions; using BizHawk.Common.BufferExtensions;
using BizHawk.Common.IOExtensions; using BizHawk.Common.IOExtensions;
using BizHawk.Common; using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
@ -11,22 +12,23 @@ namespace BizHawk.Client.Common
{ {
public static void SaveStateFile(string filename, string name) public static void SaveStateFile(string filename, string name)
{ {
var core = Global.Emulator as IStatable;
// the old method of text savestate save is now gone. // the old method of text savestate save is now gone.
// a text savestate is just like a binary savestate, but with a different core lump // a text savestate is just like a binary savestate, but with a different core lump
using (var bs = new BinaryStateSaver(filename)) using (var bs = new BinaryStateSaver(filename))
{ {
if (Global.Config.SaveStateType == Config.SaveStateTypeE.Text || if (Global.Config.SaveStateType == Config.SaveStateTypeE.Text ||
(Global.Config.SaveStateType == Config.SaveStateTypeE.Default && !Global.Emulator.BinarySaveStatesPreferred)) (Global.Config.SaveStateType == Config.SaveStateTypeE.Default && !core.BinarySaveStatesPreferred))
{ {
// text savestate format // text savestate format
using (new SimpleTime("Save Core")) using (new SimpleTime("Save Core"))
bs.PutLump(BinaryStateLump.CorestateText, (tw) => Global.Emulator.SaveStateText(tw)); bs.PutLump(BinaryStateLump.CorestateText, (tw) => core.SaveStateText(tw));
} }
else else
{ {
// binary core lump format // binary core lump format
using (new SimpleTime("Save Core")) using (new SimpleTime("Save Core"))
bs.PutLump(BinaryStateLump.Corestate, bw => Global.Emulator.SaveStateBinary(bw)); bs.PutLump(BinaryStateLump.Corestate, bw => core.SaveStateBinary(bw));
} }
if (Global.Config.SaveScreenshotWithStates) if (Global.Config.SaveScreenshotWithStates)
@ -75,6 +77,8 @@ namespace BizHawk.Client.Common
public static bool LoadStateFile(string path, string name) public static bool LoadStateFile(string path, string name)
{ {
var core = Global.Emulator as IStatable;
// try to detect binary first // try to detect binary first
var bl = BinaryStateLoader.LoadAndDetect(path); var bl = BinaryStateLoader.LoadAndDetect(path);
if (bl != null) if (bl != null)
@ -99,7 +103,7 @@ namespace BizHawk.Client.Common
} }
using (new SimpleTime("Load Core")) using (new SimpleTime("Load Core"))
bl.GetCoreState(br => Global.Emulator.LoadStateBinary(br), tr => Global.Emulator.LoadStateText(tr)); bl.GetCoreState(br => core.LoadStateBinary(br), tr => core.LoadStateText(tr));
bl.GetLump(BinaryStateLump.Framebuffer, false, PopulateFramebuffer); bl.GetLump(BinaryStateLump.Framebuffer, false, PopulateFramebuffer);
} }
@ -120,7 +124,7 @@ namespace BizHawk.Client.Common
{ {
using (var reader = new StreamReader(path)) using (var reader = new StreamReader(path))
{ {
Global.Emulator.LoadStateText(reader); core.LoadStateText(reader);
while (true) while (true)
{ {

View File

@ -1,13 +1,14 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using BizHawk.Common; using BizHawk.Common;
using BizHawk.Emulation.Common; using BizHawk.Emulation.Common;
using System.ComponentModel; using BizHawk.Emulation.Common.IEmulatorExtensions;
using System.Globalization;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
@ -24,7 +25,15 @@ namespace BizHawk.Client.Common
public TasMovie(string path, bool startsFromSavestate = false) : base(path) public TasMovie(string path, bool startsFromSavestate = false) : base(path)
{ {
// TODO: how to call the default constructor AND the base(path) constructor? And is base(path) calling base() ? // TODO: how to call the default constructor AND the base(path) constructor? And is base(path) calling base() ?
StateManager = new TasStateManager(this);
if (!Global.Emulator.HasSavestates())
{
throw new InvalidOperationException("Cannot create a TasMovie against a core that does not implement IStatable");
}
var core = (IStatable)Global.Emulator;
StateManager = new TasStateManager(this, core);
Header[HeaderKeys.MOVIEVERSION] = "BizHawk v2.0 Tasproj v1.0"; Header[HeaderKeys.MOVIEVERSION] = "BizHawk v2.0 Tasproj v1.0";
Markers = new TasMovieMarkerList(this); Markers = new TasMovieMarkerList(this);
Markers.CollectionChanged += Markers_CollectionChanged; Markers.CollectionChanged += Markers_CollectionChanged;
@ -34,7 +43,14 @@ namespace BizHawk.Client.Common
public TasMovie(bool startsFromSavestate = false) public TasMovie(bool startsFromSavestate = false)
: base() : base()
{ {
StateManager = new TasStateManager(this); if (!Global.Emulator.HasSavestates())
{
throw new InvalidOperationException("Cannot create a TasMovie against a core that does not implement IStatable");
}
var core = (IStatable)Global.Emulator;
StateManager = new TasStateManager(this, core);
Header[HeaderKeys.MOVIEVERSION] = "BizHawk v2.0 Tasproj v1.0"; Header[HeaderKeys.MOVIEVERSION] = "BizHawk v2.0 Tasproj v1.0";
Markers = new TasMovieMarkerList(this); Markers = new TasMovieMarkerList(this);
Markers.CollectionChanged += Markers_CollectionChanged; Markers.CollectionChanged += Markers_CollectionChanged;

View File

@ -5,6 +5,9 @@ using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
/// <summary> /// <summary>
@ -13,6 +16,7 @@ namespace BizHawk.Client.Common
/// </summary> /// </summary>
public class TasStateManager public class TasStateManager
{ {
private readonly IStatable Core;
private readonly SortedList<int, byte[]> States = new SortedList<int, byte[]>(); private readonly SortedList<int, byte[]> States = new SortedList<int, byte[]>();
private readonly TasMovie _movie; private readonly TasMovie _movie;
@ -40,17 +44,19 @@ namespace BizHawk.Client.Common
} }
} }
public TasStateManager(TasMovie movie) public TasStateManager(TasMovie movie, IStatable core)
{ {
_movie = movie; _movie = movie;
Core = core;
Settings = new TasStateManagerSettings(Global.Config.DefaultTasProjSettings); Settings = new TasStateManagerSettings(Global.Config.DefaultTasProjSettings);
var cap = Settings.Cap; var cap = Settings.Cap;
int limit = 0; int limit = 0;
if (Global.Emulator != null) if (!Global.Emulator.IsNull())
{ {
_expectedStateSize = Global.Emulator.SaveStateBinary().Length; _expectedStateSize = Core.SaveStateBinary().Length;
if (_expectedStateSize > 0) if (_expectedStateSize > 0)
{ {
@ -131,7 +137,7 @@ namespace BizHawk.Client.Common
if (shouldCapture) if (shouldCapture)
{ {
var frame = Global.Emulator.Frame; var frame = Global.Emulator.Frame;
var state = (byte[])Global.Emulator.SaveStateBinary().Clone(); var state = (byte[])Core.SaveStateBinary().Clone();
if (States.ContainsKey(frame)) if (States.ContainsKey(frame))
{ {

View File

@ -1,6 +1,9 @@
using System; using System;
using System.IO; using System.IO;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
namespace BizHawk.Client.Common namespace BizHawk.Client.Common
{ {
public class Rewinder public class Rewinder
@ -51,78 +54,84 @@ namespace BizHawk.Client.Common
// TOOD: this should not be parameterless?! It is only possible due to passing a static context in // TOOD: this should not be parameterless?! It is only possible due to passing a static context in
public void CaptureRewindState() public void CaptureRewindState()
{ {
if (_rewindImpossible) if (Global.Emulator.HasSavestates())
{ {
return; if (_rewindImpossible)
} {
return;
}
if (_lastState == null) if (_lastState == null)
{ {
DoRewindSettings(); DoRewindSettings();
} }
// log a frame // log a frame
if (_lastState != null && Global.Emulator.Frame % _rewindFrequency == 0) if (_lastState != null && Global.Emulator.Frame % _rewindFrequency == 0)
{ {
_rewindThread.Capture(Global.Emulator.SaveStateBinary()); _rewindThread.Capture(((IStatable)Global.Emulator).SaveStateBinary());
}
} }
} }
public void DoRewindSettings() public void DoRewindSettings()
{ {
// This is the first frame. Capture the state, and put it in LastState for future deltas to be compared against. if (Global.Emulator.HasSavestates())
_lastState = (byte[])Global.Emulator.SaveStateBinary().Clone(); {
// This is the first frame. Capture the state, and put it in LastState for future deltas to be compared against.
_lastState = (byte[]) ((IStatable)Global.Emulator).SaveStateBinary().Clone();
int state_size; int state_size;
if (_lastState.Length >= Global.Config.Rewind_LargeStateSize) if (_lastState.Length >= Global.Config.Rewind_LargeStateSize)
{
SetRewindParams(Global.Config.RewindEnabledLarge, Global.Config.RewindFrequencyLarge);
state_size = 3;
}
else if (_lastState.Length >= Global.Config.Rewind_MediumStateSize)
{
SetRewindParams(Global.Config.RewindEnabledMedium, Global.Config.RewindFrequencyMedium);
state_size = 2;
}
else
{
SetRewindParams(Global.Config.RewindEnabledSmall, Global.Config.RewindFrequencySmall);
state_size = 1;
}
var rewind_enabled = false;
if (state_size == 1)
{
rewind_enabled = Global.Config.RewindEnabledSmall;
}
else if (state_size == 2)
{
rewind_enabled = Global.Config.RewindEnabledMedium;
}
else if (state_size == 3)
{
rewind_enabled = Global.Config.RewindEnabledLarge;
}
_rewindDeltaEnable = Global.Config.Rewind_UseDelta;
if (rewind_enabled)
{
var cap = Global.Config.Rewind_BufferSize * (long)1024 * 1024;
if (_rewindBuffer != null)
{ {
_rewindBuffer.Dispose(); SetRewindParams(Global.Config.RewindEnabledLarge, Global.Config.RewindFrequencyLarge);
state_size = 3;
}
else if (_lastState.Length >= Global.Config.Rewind_MediumStateSize)
{
SetRewindParams(Global.Config.RewindEnabledMedium, Global.Config.RewindFrequencyMedium);
state_size = 2;
}
else
{
SetRewindParams(Global.Config.RewindEnabledSmall, Global.Config.RewindFrequencySmall);
state_size = 1;
} }
_rewindBuffer = new StreamBlobDatabase(Global.Config.Rewind_OnDisk, cap, BufferManage); var rewind_enabled = false;
if (state_size == 1)
if (_rewindThread != null)
{ {
_rewindThread.Dispose(); rewind_enabled = Global.Config.RewindEnabledSmall;
}
else if (state_size == 2)
{
rewind_enabled = Global.Config.RewindEnabledMedium;
}
else if (state_size == 3)
{
rewind_enabled = Global.Config.RewindEnabledLarge;
} }
_rewindThread = new RewindThreader(this, Global.Config.Rewind_IsThreaded); _rewindDeltaEnable = Global.Config.Rewind_UseDelta;
if (rewind_enabled)
{
var cap = Global.Config.Rewind_BufferSize * (long)1024 * 1024;
if (_rewindBuffer != null)
{
_rewindBuffer.Dispose();
}
_rewindBuffer = new StreamBlobDatabase(Global.Config.Rewind_OnDisk, cap, BufferManage);
if (_rewindThread != null)
{
_rewindThread.Dispose();
}
_rewindThread = new RewindThreader(this, Global.Config.Rewind_IsThreaded);
}
} }
} }
@ -346,29 +355,32 @@ namespace BizHawk.Client.Common
private void RewindDelta(bool isSmall) private void RewindDelta(bool isSmall)
{ {
var ms = _rewindBuffer.PopMemoryStream(); if (Global.Emulator.HasSavestates())
var reader = new BinaryReader(ms);
var fullstate = reader.ReadBoolean();
if (fullstate)
{ {
Global.Emulator.LoadStateBinary(reader); var ms = _rewindBuffer.PopMemoryStream();
} var reader = new BinaryReader(ms);
else var fullstate = reader.ReadBoolean();
{ if (fullstate)
var output = new MemoryStream(_lastState);
while (ms.Position < ms.Length)
{ {
var len = reader.ReadByte(); ((IStatable)Global.Emulator).LoadStateBinary(reader);
int offset = isSmall ? reader.ReadUInt16() : reader.ReadInt32();
output.Position = offset;
output.Write(ms.GetBuffer(), (int)ms.Position, len);
ms.Position += len;
} }
else
{
var output = new MemoryStream(_lastState);
while (ms.Position < ms.Length)
{
var len = reader.ReadByte();
int offset = isSmall ? reader.ReadUInt16() : reader.ReadInt32();
reader.Close(); output.Position = offset;
output.Position = 0; output.Write(ms.GetBuffer(), (int)ms.Position, len);
Global.Emulator.LoadStateBinary(new BinaryReader(output)); ms.Position += len;
}
reader.Close();
output.Position = 0;
((IStatable)Global.Emulator).LoadStateBinary(new BinaryReader(output));
}
} }
} }
} }

View File

@ -4,6 +4,7 @@ using System.Windows.Forms;
using BizHawk.Client.Common; using BizHawk.Client.Common;
using BizHawk.Emulation.Common; using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES; using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES;
using BizHawk.Emulation.Cores.Nintendo.NES; using BizHawk.Emulation.Cores.Nintendo.NES;
using BizHawk.Emulation.Cores.Nintendo.SNES9X; using BizHawk.Emulation.Cores.Nintendo.SNES9X;
@ -46,15 +47,15 @@ namespace BizHawk.Client.EmuHawk
Global.Config.RecentMovies.Add(movie.Filename); Global.Config.RecentMovies.Add(movie.Filename);
if (movie.StartsFromSavestate) if (Global.Emulator.HasSavestates() && movie.StartsFromSavestate)
{ {
if (movie.TextSavestate != null) if (movie.TextSavestate != null)
{ {
Global.Emulator.LoadStateText(new StringReader(movie.TextSavestate)); (Global.Emulator as IStatable).LoadStateText(new StringReader(movie.TextSavestate));
} }
else else
{ {
Global.Emulator.LoadStateBinary(new BinaryReader(new MemoryStream(movie.BinarySavestate, false))); (Global.Emulator as IStatable).LoadStateBinary(new BinaryReader(new MemoryStream(movie.BinarySavestate, false)));
} }
if (movie.SavestateFramebuffer != null) if (movie.SavestateFramebuffer != null)
{ {

View File

@ -3,6 +3,7 @@ using System.Windows.Forms;
using System.Drawing; using System.Drawing;
using BizHawk.Client.Common; using BizHawk.Client.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk namespace BizHawk.Client.EmuHawk
{ {
@ -33,7 +34,7 @@ namespace BizHawk.Client.EmuHawk
DiskBufferCheckbox.Checked = Global.Config.Rewind_OnDisk; DiskBufferCheckbox.Checked = Global.Config.Rewind_OnDisk;
RewindIsThreadedCheckbox.Checked = Global.Config.Rewind_IsThreaded; RewindIsThreadedCheckbox.Checked = Global.Config.Rewind_IsThreaded;
_stateSize = Global.Emulator.SaveStateBinary().Length; _stateSize = ((IStatable)Global.Emulator).SaveStateBinary().Length;
BufferSizeUpDown.Value = Global.Config.Rewind_BufferSize; BufferSizeUpDown.Value = Global.Config.Rewind_BufferSize;
_mediumStateSize = Global.Config.Rewind_MediumStateSize; _mediumStateSize = Global.Config.Rewind_MediumStateSize;
@ -295,7 +296,7 @@ namespace BizHawk.Client.EmuHawk
} }
else else
{ {
avg_state_size = Global.Emulator.SaveStateBinary().Length; avg_state_size = _stateSize;
} }
} }
else else

View File

@ -5,6 +5,7 @@ using System.Linq;
using BizHawk.Common.ReflectionExtensions; using BizHawk.Common.ReflectionExtensions;
using BizHawk.Emulation.Common; using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
using BizHawk.Client.Common; using BizHawk.Client.Common;
using BizHawk.Client.Common.MovieConversionExtensions; using BizHawk.Client.Common.MovieConversionExtensions;
@ -69,19 +70,21 @@ namespace BizHawk.Client.EmuHawk
Directory.CreateDirectory(fileInfo.DirectoryName); Directory.CreateDirectory(fileInfo.DirectoryName);
} }
if (StartFromCombo.SelectedItem.ToString() == "Now") if (StartFromCombo.SelectedItem.ToString() == "Now" && Global.Emulator.HasSavestates())
{ {
var core = Global.Emulator as IStatable;
movieToRecord.StartsFromSavestate = true; movieToRecord.StartsFromSavestate = true;
if (Global.Emulator.BinarySaveStatesPreferred) if (core.BinarySaveStatesPreferred)
{ {
movieToRecord.BinarySavestate = (byte[])Global.Emulator.SaveStateBinary().Clone(); movieToRecord.BinarySavestate = (byte[])core.SaveStateBinary().Clone();
} }
else else
{ {
using (var sw = new StringWriter()) using (var sw = new StringWriter())
{ {
Global.Emulator.SaveStateText(sw); core.SaveStateText(sw);
movieToRecord.TextSavestate = sw.ToString(); movieToRecord.TextSavestate = sw.ToString();
} }
} }

View File

@ -7,6 +7,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using BizHawk.Emulation.Common;
using BizHawk.Client.Common; using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk namespace BizHawk.Client.EmuHawk
@ -23,7 +24,7 @@ namespace BizHawk.Client.EmuHawk
private void GreenzoneSettings_Load(object sender, EventArgs e) private void GreenzoneSettings_Load(object sender, EventArgs e)
{ {
_stateSizeMb = Global.Emulator.SaveStateBinary().Length / (decimal)1024 / (decimal)1024; _stateSizeMb = ((IStatable)Global.Emulator).SaveStateBinary().Length / (decimal)1024 / (decimal)1024;
SaveGreenzoneCheckbox.Checked = Settings.SaveGreenzone; SaveGreenzoneCheckbox.Checked = Settings.SaveGreenzone;
CapacityNumeric.Value = Settings.Capacitymb == 0 ? 1 : Settings.Capacitymb < CapacityNumeric.Maximum ? CapacityNumeric.Value = Settings.Capacitymb == 0 ? 1 : Settings.Capacitymb < CapacityNumeric.Maximum ?

View File

@ -10,6 +10,7 @@ using BizHawk.Client.Common;
using BizHawk.Client.Common.MovieConversionExtensions; using BizHawk.Client.Common.MovieConversionExtensions;
using BizHawk.Client.EmuHawk.ToolExtensions; using BizHawk.Client.EmuHawk.ToolExtensions;
using BizHawk.Client.EmuHawk.WinFormExtensions; using BizHawk.Client.EmuHawk.WinFormExtensions;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.EmuHawk namespace BizHawk.Client.EmuHawk
{ {
@ -507,7 +508,7 @@ namespace BizHawk.Client.EmuHawk
if (CurrentTasMovie.TasStateManager.HasState(frame)) if (CurrentTasMovie.TasStateManager.HasState(frame))
{ {
var state = (byte[])Global.Emulator.SaveStateBinary().Clone(); var state = (byte[])(((IStatable)Global.Emulator).SaveStateBinary().Clone());
var greenzone = CurrentTasMovie.TasStateManager[frame]; var greenzone = CurrentTasMovie.TasStateManager[frame];
if (!state.SequenceEqual(greenzone.Value)) if (!state.SequenceEqual(greenzone.Value))
@ -749,7 +750,7 @@ namespace BizHawk.Client.EmuHawk
var newProject = CurrentTasMovie.ConvertToSavestateAnchoredMovie( var newProject = CurrentTasMovie.ConvertToSavestateAnchoredMovie(
index, index,
(byte[])Global.Emulator.SaveStateBinary().Clone()); (byte[])((IStatable)Global.Emulator).SaveStateBinary().Clone());
GlobalWin.MainForm.PauseEmulator(); GlobalWin.MainForm.PauseEmulator();
LoadProject(newProject.Filename); LoadProject(newProject.Filename);

View File

@ -5,6 +5,8 @@ using System.Linq;
using System.Windows.Forms; using System.Windows.Forms;
using System.ComponentModel; using System.ComponentModel;
using BizHawk.Emulation.Common;
using BizHawk.Client.Common; using BizHawk.Client.Common;
using BizHawk.Client.Common.MovieConversionExtensions; using BizHawk.Client.Common.MovieConversionExtensions;
@ -313,7 +315,7 @@ namespace BizHawk.Client.EmuHawk
private void LoadState(KeyValuePair<int, byte[]> state) private void LoadState(KeyValuePair<int, byte[]> state)
{ {
Global.Emulator.LoadStateBinary(new BinaryReader(new MemoryStream(state.Value.ToArray()))); ((IStatable)Global.Emulator).LoadStateBinary(new BinaryReader(new MemoryStream(state.Value.ToArray())));
if (state.Key == 0 && CurrentTasMovie.StartsFromSavestate) if (state.Key == 0 && CurrentTasMovie.StartsFromSavestate)
{ {

View File

@ -68,6 +68,7 @@
<Compile Include="Interfaces\ISaveRam.cs" /> <Compile Include="Interfaces\ISaveRam.cs" />
<Compile Include="Interfaces\ISettable.cs" /> <Compile Include="Interfaces\ISettable.cs" />
<Compile Include="Interfaces\ISoundProvider.cs" /> <Compile Include="Interfaces\ISoundProvider.cs" />
<Compile Include="Interfaces\IStatable.cs" />
<Compile Include="Interfaces\ISyncSoundProvider.cs" /> <Compile Include="Interfaces\ISyncSoundProvider.cs" />
<Compile Include="Interfaces\IVideoProvider.cs" /> <Compile Include="Interfaces\IVideoProvider.cs" />
<Compile Include="MemoryDomain.cs" /> <Compile Include="MemoryDomain.cs" />

View File

@ -22,6 +22,11 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions
return core is ISaveRam; return core is ISaveRam;
} }
public static bool HasSavestates(this IEmulator core)
{
return core is IStatable;
}
public static bool IsNull(this IEmulator core) public static bool IsNull(this IEmulator core)
{ {
return core == null || core is NullEmulator; return core == null || core is NullEmulator;

View File

@ -83,25 +83,6 @@ namespace BizHawk.Emulation.Common
/// </summary> /// </summary>
void ResetCounters(); void ResetCounters();
/// <summary>
/// Savestate handling methods
/// </summary>
/// <param name="writer"></param>
void SaveStateText(TextWriter writer);
void LoadStateText(TextReader reader);
void SaveStateBinary(BinaryWriter writer);
void LoadStateBinary(BinaryReader reader);
/// <summary>
/// save state binary to a byte buffer
/// </summary>
/// <returns>you may NOT modify this. if you call SaveStateBinary() again with the same core, the old data MAY be overwritten.</returns>
byte[] SaveStateBinary();
/// <summary>
/// true if the core would rather give a binary savestate than a text one. both must function regardless
/// </summary>
bool BinarySaveStatesPreferred { get; }
/// <summary> /// <summary>
/// the corecomm module in use by this core. /// the corecomm module in use by this core.
/// </summary> /// </summary>

View File

@ -0,0 +1,27 @@
using System.IO;
namespace BizHawk.Emulation.Common
{
/// <summary>
/// Savestate handling methods
/// </summary>
public interface IStatable : ICoreService, IEmulator
{
void SaveStateText(TextWriter writer);
void LoadStateText(TextReader reader);
void SaveStateBinary(BinaryWriter writer);
void LoadStateBinary(BinaryReader reader);
/// <summary>
/// save state binary to a byte buffer
/// </summary>
/// <returns>you may NOT modify this. if you call SaveStateBinary() again with the same core, the old data MAY be overwritten.</returns>
byte[] SaveStateBinary();
/// <summary>
/// true if the core would rather give a binary savestate than a text one. both must function regardless
/// </summary>
bool BinarySaveStatesPreferred { get; }
}
}

View File

@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Calculators
isPorted: false, isPorted: false,
isReleased: true isReleased: true
)] )]
public partial class TI83 : IEmulator, IMemoryDomains, IDebuggable, ISettable<TI83.TI83Settings, object> public partial class TI83 : IEmulator, IMemoryDomains, IStatable, IDebuggable, ISettable<TI83.TI83Settings, object>
{ {
//hardware //hardware
private readonly Z80A cpu = new Z80A(); private readonly Z80A cpu = new Z80A();

View File

@ -13,7 +13,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
isPorted: false, isPorted: false,
isReleased: false isReleased: false
)] )]
sealed public partial class C64 : IEmulator, IMemoryDomains sealed public partial class C64 : IEmulator, IMemoryDomains, IStatable
{ {
// internal variables // internal variables
private bool _islag = true; private bool _islag = true;

View File

@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
isPorted: false, isPorted: false,
isReleased: true isReleased: true
)] )]
public partial class Atari2600 : IEmulator, IMemoryDomains, IDebuggable, ISettable<Atari2600.A2600Settings, Atari2600.A2600SyncSettings> public partial class Atari2600 : IEmulator, IMemoryDomains, IStatable, IDebuggable, ISettable<Atari2600.A2600Settings, Atari2600.A2600SyncSettings>
{ {
private readonly GameInfo _game; private readonly GameInfo _game;
private bool _islag = true; private bool _islag = true;

View File

@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari7800
portedVersion: "v1.5", portedVersion: "v1.5",
portedUrl: "http://emu7800.sourceforge.net/" portedUrl: "http://emu7800.sourceforge.net/"
)] )]
public partial class Atari7800 : IEmulator, IMemoryDomains, ISaveRam, IDebuggable public partial class Atari7800 : IEmulator, IMemoryDomains, ISaveRam, IDebuggable, IStatable
{ {
// TODO: // TODO:
// some things don't work when you try to plug in a 2600 game // some things don't work when you try to plug in a 2600 game

View File

@ -12,7 +12,7 @@ using Newtonsoft.Json;
namespace BizHawk.Emulation.Cores.Atari.Lynx namespace BizHawk.Emulation.Cores.Atari.Lynx
{ {
[CoreAttributes("Handy", "K. Wilkins", true, true, "mednafen 0-9-34-1", "http://mednafen.sourceforge.net/")] [CoreAttributes("Handy", "K. Wilkins", true, true, "mednafen 0-9-34-1", "http://mednafen.sourceforge.net/")]
public class Lynx : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam public class Lynx : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam, IStatable
{ {
IntPtr Core; IntPtr Core;

View File

@ -159,38 +159,6 @@ namespace BizHawk.Emulation.Cores.Intellivision
//IsLagFrame = false; //IsLagFrame = false;
} }
[FeatureNotImplemented]
public void SaveStateText(TextWriter writer)
{
throw new NotImplementedException();
}
[FeatureNotImplemented]
public void LoadStateText(TextReader reader)
{
throw new NotImplementedException();
}
[FeatureNotImplemented]
public void SaveStateBinary(BinaryWriter writer)
{
throw new NotImplementedException();
}
[FeatureNotImplemented]
public void LoadStateBinary(BinaryReader reader)
{
throw new NotImplementedException();
}
[FeatureNotImplemented]
public byte[] SaveStateBinary()
{
throw new NotImplementedException();
}
public bool BinarySaveStatesPreferred { get { return false; } }
public CoreComm CoreComm { get; private set; } public CoreComm CoreComm { get; private set; }
public void Dispose() public void Dispose()

View File

@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
isPorted: true, isPorted: true,
isReleased: false isReleased: false
)] )]
public class GBA : IEmulator, IVideoProvider, ISyncSoundProvider, IGBAGPUViewable, IMemoryDomains, ISaveRam, IDebuggable public class GBA : IEmulator, IVideoProvider, ISyncSoundProvider, IGBAGPUViewable, IMemoryDomains, ISaveRam, IDebuggable, IStatable
{ {
public IDictionary<string, int> GetCpuFlagsAndRegisters() public IDictionary<string, int> GetCpuFlagsAndRegisters()
{ {

View File

@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
{ {
[CoreAttributes("VBA-Next", "many authors", true, true, "cd508312a29ed8c29dacac1b11c2dce56c338a54", "https://github.com/libretro/vba-next")] [CoreAttributes("VBA-Next", "many authors", true, true, "cd508312a29ed8c29dacac1b11c2dce56c338a54", "https://github.com/libretro/vba-next")]
public class VBANext : IEmulator, IVideoProvider, ISyncSoundProvider, public class VBANext : IEmulator, IVideoProvider, ISyncSoundProvider,
IGBAGPUViewable, IMemoryDomains, ISaveRam, IDebuggable, ISettable<object, VBANext.SyncSettings> IGBAGPUViewable, IMemoryDomains, ISaveRam, IStatable, IDebuggable, ISettable<object, VBANext.SyncSettings>
{ {
IntPtr Core; IntPtr Core;

View File

@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
portedVersion: "SVN 344", portedVersion: "SVN 344",
portedUrl: "http://gambatte.sourceforge.net/" portedUrl: "http://gambatte.sourceforge.net/"
)] )]
public class Gameboy : IEmulator, IVideoProvider, ISyncSoundProvider, ISaveRam, public class Gameboy : IEmulator, IVideoProvider, ISyncSoundProvider, ISaveRam, IStatable,
IMemoryDomains, IDebuggable, ISettable<Gameboy.GambatteSettings, Gameboy.GambatteSyncSettings> IMemoryDomains, IDebuggable, ISettable<Gameboy.GambatteSettings, Gameboy.GambatteSyncSettings>
{ {
#region ALL SAVESTATEABLE STATE GOES HERE #region ALL SAVESTATEABLE STATE GOES HERE

View File

@ -17,7 +17,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
portedVersion: "2.0", portedVersion: "2.0",
portedUrl: "https://code.google.com/p/mupen64plus/" portedUrl: "https://code.google.com/p/mupen64plus/"
)] )]
public partial class N64 : IEmulator, IMemoryDomains, ISaveRam, IDebuggable, public partial class N64 : IEmulator, IMemoryDomains, ISaveRam, IDebuggable, IStatable,
ISettable<N64Settings, N64SyncSettings> ISettable<N64Settings, N64SyncSettings>
{ {
private readonly N64Input _inputProvider; private readonly N64Input _inputProvider;

View File

@ -17,7 +17,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
isPorted: false, isPorted: false,
isReleased: true isReleased: true
)] )]
public partial class NES : IEmulator, IMemoryDomains, ISaveRam, IDebuggable, public partial class NES : IEmulator, IMemoryDomains, ISaveRam, IDebuggable, IStatable,
ISettable<NES.NESSettings, NES.NESSyncSettings> ISettable<NES.NESSettings, NES.NESSyncSettings>
{ {
static readonly bool USE_DATABASE = true; static readonly bool USE_DATABASE = true;

View File

@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
portedVersion: "0.7.0", portedVersion: "0.7.0",
portedUrl: "https://github.com/kode54/QuickNES" portedUrl: "https://github.com/kode54/QuickNES"
)] )]
public class QuickNES : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam, public class QuickNES : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam, IStatable,
IDebuggable, ISettable<QuickNES.QuickNESSettings, QuickNES.QuickNESSyncSettings> IDebuggable, ISettable<QuickNES.QuickNESSettings, QuickNES.QuickNESSyncSettings>
{ {
#region FPU precision #region FPU precision

View File

@ -29,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
portedVersion: "v87", portedVersion: "v87",
portedUrl: "http://byuu.org/" portedUrl: "http://byuu.org/"
)] )]
public unsafe class LibsnesCore : IEmulator, IVideoProvider, IMemoryDomains, ISaveRam, public unsafe class LibsnesCore : IEmulator, IVideoProvider, IMemoryDomains, ISaveRam, IStatable,
IDebuggable, ISettable<LibsnesCore.SnesSettings, LibsnesCore.SnesSyncSettings> IDebuggable, ISettable<LibsnesCore.SnesSettings, LibsnesCore.SnesSyncSettings>
{ {
public LibsnesCore(GameInfo game, byte[] romData, bool deterministicEmulation, byte[] xmlData, CoreComm comm, object Settings, object SyncSettings) public LibsnesCore(GameInfo game, byte[] romData, bool deterministicEmulation, byte[] xmlData, CoreComm comm, object Settings, object SyncSettings)

View File

@ -61,33 +61,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
public string BoardName { get { return null; } } public string BoardName { get { return null; } }
public CoreComm CoreComm { get; private set; } public CoreComm CoreComm { get; private set; }
#region savestates
public void SaveStateText(System.IO.TextWriter writer)
{
}
public void LoadStateText(System.IO.TextReader reader)
{
}
public void SaveStateBinary(System.IO.BinaryWriter writer)
{
}
public void LoadStateBinary(System.IO.BinaryReader reader)
{
}
public byte[] SaveStateBinary()
{
return new byte[0];
}
public bool BinarySaveStatesPreferred { get { return true; } }
#endregion
#region IVideoProvider #region IVideoProvider
private int[] _vbuff = new int[512 * 480]; private int[] _vbuff = new int[512 * 480];

View File

@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
isPorted: false, isPorted: false,
isReleased: true isReleased: true
)] )]
public sealed partial class PCEngine : IEmulator, IMemoryDomains, ISaveRam, public sealed partial class PCEngine : IEmulator, IMemoryDomains, ISaveRam, IStatable,
IDebuggable, ISettable<PCEngine.PCESettings, PCEngine.PCESyncSettings> IDebuggable, ISettable<PCEngine.PCESettings, PCEngine.PCESyncSettings>
{ {
// ROM // ROM

View File

@ -21,7 +21,7 @@ namespace BizHawk.Emulation.Cores.Sega.Genesis
isPorted: false, isPorted: false,
isReleased: false isReleased: false
)] )]
public sealed partial class Genesis : IEmulator, IMemoryDomains, IDebuggable, ISaveRam public sealed partial class Genesis : IEmulator, IMemoryDomains, IDebuggable, ISaveRam, IStatable
{ {
private int _lagcount = 0; private int _lagcount = 0;
private bool lagged = true; private bool lagged = true;

View File

@ -23,7 +23,7 @@ namespace BizHawk.Emulation.Cores.Sega.Saturn
portedVersion: "9.12", portedVersion: "9.12",
portedUrl: "http://yabause.org" portedUrl: "http://yabause.org"
)] )]
public class Yabause : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam, public class Yabause : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam, IStatable,
ISettable<object, Yabause.SaturnSyncSettings> ISettable<object, Yabause.SaturnSyncSettings>
{ {
public static ControllerDefinition SaturnController = new ControllerDefinition public static ControllerDefinition SaturnController = new ControllerDefinition

View File

@ -24,7 +24,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
portedVersion: "r874", portedVersion: "r874",
portedUrl: "https://code.google.com/p/genplus-gx/" portedUrl: "https://code.google.com/p/genplus-gx/"
)] )]
public class GPGX : IEmulator, ISyncSoundProvider, IVideoProvider, IMemoryDomains, ISaveRam, public class GPGX : IEmulator, ISyncSoundProvider, IVideoProvider, IMemoryDomains, ISaveRam, IStatable,
IDebuggable, ISettable<GPGX.GPGXSettings, GPGX.GPGXSyncSettings> IDebuggable, ISettable<GPGX.GPGXSettings, GPGX.GPGXSyncSettings>
{ {
static GPGX AttachedCore = null; static GPGX AttachedCore = null;

View File

@ -43,7 +43,6 @@ namespace BizHawk.Emulation.Cores.Sony.PSP
public IController Controller { get; set; } public IController Controller { get; set; }
public bool DeterministicEmulation { get { return true; } } public bool DeterministicEmulation { get { return true; } }
public string SystemId { get { return "PSP"; } } public string SystemId { get { return "PSP"; } }
public bool BinarySaveStatesPreferred { get { return true; } }
public CoreComm CoreComm { get; private set; } public CoreComm CoreComm { get; private set; }
public string BoardName { get { return null; } } public string BoardName { get { return null; } }
@ -149,32 +148,6 @@ namespace BizHawk.Emulation.Cores.Sony.PSP
{ {
} }
[FeatureNotImplemented]
public void SaveStateText(System.IO.TextWriter writer)
{
}
[FeatureNotImplemented]
public void LoadStateText(System.IO.TextReader reader)
{
}
[FeatureNotImplemented]
public void SaveStateBinary(System.IO.BinaryWriter writer)
{
}
[FeatureNotImplemented]
public void LoadStateBinary(System.IO.BinaryReader reader)
{
}
[FeatureNotImplemented]
public byte[] SaveStateBinary()
{
return new byte[0];
}
const int screenwidth = 480; const int screenwidth = 480;
const int screenheight = 272; const int screenheight = 272;
readonly int[] screenbuffer = new int[screenwidth * screenheight]; readonly int[] screenbuffer = new int[screenwidth * screenheight];

View File

@ -285,23 +285,6 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
[FeatureNotImplemented] [FeatureNotImplemented]
public bool DeterministicEmulation { get { return true; } } public bool DeterministicEmulation { get { return true; } }
[FeatureNotImplemented]
public void SaveStateText(TextWriter writer) { }
[FeatureNotImplemented]
public void LoadStateText(TextReader reader) { }
[FeatureNotImplemented]
public void SaveStateBinary(BinaryWriter writer) { }
[FeatureNotImplemented]
public void LoadStateBinary(BinaryReader reader) { }
[FeatureNotImplemented]
public byte[] SaveStateBinary() { return new byte[1]; }
[FeatureNotImplemented]
public bool BinarySaveStatesPreferred { get { return false; } }
public int[] GetVideoBuffer() { return frameBuffer; } public int[] GetVideoBuffer() { return frameBuffer; }
public int VirtualWidth { get; private set; } public int VirtualWidth { get; private set; }
public int VirtualHeight { get { return BufferHeight; } } public int VirtualHeight { get { return BufferHeight; } }

View File

@ -12,7 +12,7 @@ using System.Runtime.InteropServices;
namespace BizHawk.Emulation.Cores.WonderSwan namespace BizHawk.Emulation.Cores.WonderSwan
{ {
[CoreAttributes("Cygne/Mednafen", "Dox", true, true, "0.9.36.5", "http://mednafen.sourceforge.net/")] [CoreAttributes("Cygne/Mednafen", "Dox", true, true, "0.9.36.5", "http://mednafen.sourceforge.net/")]
public class WonderSwan : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam, public class WonderSwan : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam, IStatable,
IDebuggable, ISettable<WonderSwan.Settings, WonderSwan.SyncSettings> IDebuggable, ISettable<WonderSwan.Settings, WonderSwan.SyncSettings>
{ {
#region Controller #region Controller