From 76148ae1111a0d6bb8719373c70f36cfe126d340 Mon Sep 17 00:00:00 2001 From: adelikat Date: Sun, 30 Nov 2014 16:42:58 +0000 Subject: [PATCH] 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) --- BizHawk.Client.Common/SavestateManager.cs | 16 +- .../movie/tasproj/TasMovie.cs | 24 ++- .../movie/tasproj/TasStateManager.cs | 14 +- BizHawk.Client.Common/rewind/Rewinder.cs | 164 ++++++++++-------- BizHawk.Client.EmuHawk/MainForm.Movie.cs | 7 +- BizHawk.Client.EmuHawk/config/RewindConfig.cs | 5 +- BizHawk.Client.EmuHawk/movie/RecordMovie.cs | 11 +- .../tools/TAStudio/GreenzoneSettings.cs | 3 +- .../tools/TAStudio/TAStudio.MenuItems.cs | 5 +- .../tools/TAStudio/TAStudio.cs | 4 +- .../BizHawk.Emulation.Common.csproj | 1 + BizHawk.Emulation.Common/Extensions.cs | 5 + .../Interfaces/IEmulator.cs | 19 -- .../Interfaces/IStatable.cs | 27 +++ BizHawk.Emulation.Cores/Calculator/TI83.cs | 2 +- .../Computers/Commodore64/C64.cs | 2 +- .../Consoles/Atari/2600/Atari2600.cs | 2 +- .../Consoles/Atari/7800/Atari7800.cs | 2 +- .../Consoles/Atari/lynx/Lynx.cs | 2 +- .../Consoles/Intellivision/Intellivision.cs | 32 ---- .../Consoles/Nintendo/GBA/Meteor.cs | 2 +- .../Consoles/Nintendo/GBA/VBANext.cs | 2 +- .../Consoles/Nintendo/Gameboy/Gambatte.cs | 2 +- .../Consoles/Nintendo/N64/N64.cs | 2 +- .../Consoles/Nintendo/NES/NES.cs | 2 +- .../Consoles/Nintendo/QuickNES/QuickNES.cs | 2 +- .../Consoles/Nintendo/SNES/LibsnesCore.cs | 2 +- .../Consoles/Nintendo/SNES9X/Snes9x.cs | 27 --- .../Consoles/PC Engine/PCEngine.cs | 2 +- .../Consoles/Sega/Genesis/Genesis.cs | 2 +- .../Consoles/Sega/Saturn/Yabause.cs | 2 +- .../Consoles/Sega/gpgx/GPGX.cs | 2 +- .../Consoles/Sony/PSP/PSP.cs | 27 --- .../Consoles/Sony/PSX/Octoshock.cs | 17 -- .../Consoles/WonderSwan/WonderSwan.cs | 2 +- 35 files changed, 200 insertions(+), 242 deletions(-) create mode 100644 BizHawk.Emulation.Common/Interfaces/IStatable.cs diff --git a/BizHawk.Client.Common/SavestateManager.cs b/BizHawk.Client.Common/SavestateManager.cs index 73c896732f..eca69a466a 100644 --- a/BizHawk.Client.Common/SavestateManager.cs +++ b/BizHawk.Client.Common/SavestateManager.cs @@ -1,9 +1,10 @@ using System; using System.IO; +using BizHawk.Common; using BizHawk.Common.BufferExtensions; using BizHawk.Common.IOExtensions; -using BizHawk.Common; +using BizHawk.Emulation.Common; namespace BizHawk.Client.Common { @@ -11,22 +12,23 @@ namespace BizHawk.Client.Common { public static void SaveStateFile(string filename, string name) { + var core = Global.Emulator as IStatable; // 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 using (var bs = new BinaryStateSaver(filename)) { 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 using (new SimpleTime("Save Core")) - bs.PutLump(BinaryStateLump.CorestateText, (tw) => Global.Emulator.SaveStateText(tw)); + bs.PutLump(BinaryStateLump.CorestateText, (tw) => core.SaveStateText(tw)); } else { // binary core lump format 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) @@ -75,6 +77,8 @@ namespace BizHawk.Client.Common public static bool LoadStateFile(string path, string name) { + var core = Global.Emulator as IStatable; + // try to detect binary first var bl = BinaryStateLoader.LoadAndDetect(path); if (bl != null) @@ -99,7 +103,7 @@ namespace BizHawk.Client.Common } 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); } @@ -120,7 +124,7 @@ namespace BizHawk.Client.Common { using (var reader = new StreamReader(path)) { - Global.Emulator.LoadStateText(reader); + core.LoadStateText(reader); while (true) { diff --git a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs index 346ff04b41..4292f57d17 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasMovie.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasMovie.cs @@ -1,13 +1,14 @@ using System; using System.Collections.Generic; +using System.ComponentModel; +using System.Globalization; using System.IO; using System.Linq; using System.Text; using BizHawk.Common; using BizHawk.Emulation.Common; -using System.ComponentModel; -using System.Globalization; +using BizHawk.Emulation.Common.IEmulatorExtensions; namespace BizHawk.Client.Common { @@ -24,7 +25,15 @@ namespace BizHawk.Client.Common 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() ? - 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"; Markers = new TasMovieMarkerList(this); Markers.CollectionChanged += Markers_CollectionChanged; @@ -34,7 +43,14 @@ namespace BizHawk.Client.Common public TasMovie(bool startsFromSavestate = false) : 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"; Markers = new TasMovieMarkerList(this); Markers.CollectionChanged += Markers_CollectionChanged; diff --git a/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs b/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs index c3108d900d..492c4b26bc 100644 --- a/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs +++ b/BizHawk.Client.Common/movie/tasproj/TasStateManager.cs @@ -5,6 +5,9 @@ using System.IO; using System.Linq; using System.Text; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.IEmulatorExtensions; + namespace BizHawk.Client.Common { /// @@ -13,6 +16,7 @@ namespace BizHawk.Client.Common /// public class TasStateManager { + private readonly IStatable Core; private readonly SortedList States = new SortedList(); private readonly TasMovie _movie; @@ -40,17 +44,19 @@ namespace BizHawk.Client.Common } } - public TasStateManager(TasMovie movie) + public TasStateManager(TasMovie movie, IStatable core) { _movie = movie; + Core = core; + Settings = new TasStateManagerSettings(Global.Config.DefaultTasProjSettings); var cap = Settings.Cap; int limit = 0; - if (Global.Emulator != null) + if (!Global.Emulator.IsNull()) { - _expectedStateSize = Global.Emulator.SaveStateBinary().Length; + _expectedStateSize = Core.SaveStateBinary().Length; if (_expectedStateSize > 0) { @@ -131,7 +137,7 @@ namespace BizHawk.Client.Common if (shouldCapture) { var frame = Global.Emulator.Frame; - var state = (byte[])Global.Emulator.SaveStateBinary().Clone(); + var state = (byte[])Core.SaveStateBinary().Clone(); if (States.ContainsKey(frame)) { diff --git a/BizHawk.Client.Common/rewind/Rewinder.cs b/BizHawk.Client.Common/rewind/Rewinder.cs index 217f498a39..53aea44454 100644 --- a/BizHawk.Client.Common/rewind/Rewinder.cs +++ b/BizHawk.Client.Common/rewind/Rewinder.cs @@ -1,6 +1,9 @@ using System; using System.IO; +using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.IEmulatorExtensions; + namespace BizHawk.Client.Common { 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 public void CaptureRewindState() { - if (_rewindImpossible) + if (Global.Emulator.HasSavestates()) { - return; - } + if (_rewindImpossible) + { + return; + } - if (_lastState == null) - { - DoRewindSettings(); - } + if (_lastState == null) + { + DoRewindSettings(); + } - // log a frame - if (_lastState != null && Global.Emulator.Frame % _rewindFrequency == 0) - { - _rewindThread.Capture(Global.Emulator.SaveStateBinary()); + // log a frame + if (_lastState != null && Global.Emulator.Frame % _rewindFrequency == 0) + { + _rewindThread.Capture(((IStatable)Global.Emulator).SaveStateBinary()); + } } } public void DoRewindSettings() { - // This is the first frame. Capture the state, and put it in LastState for future deltas to be compared against. - _lastState = (byte[])Global.Emulator.SaveStateBinary().Clone(); + if (Global.Emulator.HasSavestates()) + { + // 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; - 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) + int state_size; + if (_lastState.Length >= Global.Config.Rewind_LargeStateSize) { - _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); - - if (_rewindThread != null) + var rewind_enabled = false; + if (state_size == 1) { - _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) { - var ms = _rewindBuffer.PopMemoryStream(); - var reader = new BinaryReader(ms); - var fullstate = reader.ReadBoolean(); - if (fullstate) + if (Global.Emulator.HasSavestates()) { - Global.Emulator.LoadStateBinary(reader); - } - else - { - var output = new MemoryStream(_lastState); - while (ms.Position < ms.Length) + var ms = _rewindBuffer.PopMemoryStream(); + var reader = new BinaryReader(ms); + var fullstate = reader.ReadBoolean(); + if (fullstate) { - var len = reader.ReadByte(); - int offset = isSmall ? reader.ReadUInt16() : reader.ReadInt32(); - - output.Position = offset; - output.Write(ms.GetBuffer(), (int)ms.Position, len); - ms.Position += len; + ((IStatable)Global.Emulator).LoadStateBinary(reader); } + 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 = 0; - Global.Emulator.LoadStateBinary(new BinaryReader(output)); + output.Position = offset; + output.Write(ms.GetBuffer(), (int)ms.Position, len); + ms.Position += len; + } + + reader.Close(); + output.Position = 0; + ((IStatable)Global.Emulator).LoadStateBinary(new BinaryReader(output)); + } } } } diff --git a/BizHawk.Client.EmuHawk/MainForm.Movie.cs b/BizHawk.Client.EmuHawk/MainForm.Movie.cs index cc986910c8..ea8812e552 100644 --- a/BizHawk.Client.EmuHawk/MainForm.Movie.cs +++ b/BizHawk.Client.EmuHawk/MainForm.Movie.cs @@ -4,6 +4,7 @@ using System.Windows.Forms; using BizHawk.Client.Common; using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.IEmulatorExtensions; using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES; using BizHawk.Emulation.Cores.Nintendo.NES; using BizHawk.Emulation.Cores.Nintendo.SNES9X; @@ -46,15 +47,15 @@ namespace BizHawk.Client.EmuHawk Global.Config.RecentMovies.Add(movie.Filename); - if (movie.StartsFromSavestate) + if (Global.Emulator.HasSavestates() && movie.StartsFromSavestate) { if (movie.TextSavestate != null) { - Global.Emulator.LoadStateText(new StringReader(movie.TextSavestate)); + (Global.Emulator as IStatable).LoadStateText(new StringReader(movie.TextSavestate)); } 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) { diff --git a/BizHawk.Client.EmuHawk/config/RewindConfig.cs b/BizHawk.Client.EmuHawk/config/RewindConfig.cs index 2f75261542..248d693894 100644 --- a/BizHawk.Client.EmuHawk/config/RewindConfig.cs +++ b/BizHawk.Client.EmuHawk/config/RewindConfig.cs @@ -3,6 +3,7 @@ using System.Windows.Forms; using System.Drawing; using BizHawk.Client.Common; +using BizHawk.Emulation.Common; namespace BizHawk.Client.EmuHawk { @@ -33,7 +34,7 @@ namespace BizHawk.Client.EmuHawk DiskBufferCheckbox.Checked = Global.Config.Rewind_OnDisk; RewindIsThreadedCheckbox.Checked = Global.Config.Rewind_IsThreaded; - _stateSize = Global.Emulator.SaveStateBinary().Length; + _stateSize = ((IStatable)Global.Emulator).SaveStateBinary().Length; BufferSizeUpDown.Value = Global.Config.Rewind_BufferSize; _mediumStateSize = Global.Config.Rewind_MediumStateSize; @@ -295,7 +296,7 @@ namespace BizHawk.Client.EmuHawk } else { - avg_state_size = Global.Emulator.SaveStateBinary().Length; + avg_state_size = _stateSize; } } else diff --git a/BizHawk.Client.EmuHawk/movie/RecordMovie.cs b/BizHawk.Client.EmuHawk/movie/RecordMovie.cs index 5063fd5e72..919c60e305 100644 --- a/BizHawk.Client.EmuHawk/movie/RecordMovie.cs +++ b/BizHawk.Client.EmuHawk/movie/RecordMovie.cs @@ -5,6 +5,7 @@ using System.Linq; using BizHawk.Common.ReflectionExtensions; using BizHawk.Emulation.Common; +using BizHawk.Emulation.Common.IEmulatorExtensions; using BizHawk.Client.Common; using BizHawk.Client.Common.MovieConversionExtensions; @@ -69,19 +70,21 @@ namespace BizHawk.Client.EmuHawk 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; - if (Global.Emulator.BinarySaveStatesPreferred) + if (core.BinarySaveStatesPreferred) { - movieToRecord.BinarySavestate = (byte[])Global.Emulator.SaveStateBinary().Clone(); + movieToRecord.BinarySavestate = (byte[])core.SaveStateBinary().Clone(); } else { using (var sw = new StringWriter()) { - Global.Emulator.SaveStateText(sw); + core.SaveStateText(sw); movieToRecord.TextSavestate = sw.ToString(); } } diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.cs index 9ad2f5def3..e79b2630ac 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/GreenzoneSettings.cs @@ -7,6 +7,7 @@ using System.Linq; using System.Text; using System.Windows.Forms; +using BizHawk.Emulation.Common; using BizHawk.Client.Common; namespace BizHawk.Client.EmuHawk @@ -23,7 +24,7 @@ namespace BizHawk.Client.EmuHawk 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; CapacityNumeric.Value = Settings.Capacitymb == 0 ? 1 : Settings.Capacitymb < CapacityNumeric.Maximum ? diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index d7ee1430c9..cde3dd251a 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -10,6 +10,7 @@ using BizHawk.Client.Common; using BizHawk.Client.Common.MovieConversionExtensions; using BizHawk.Client.EmuHawk.ToolExtensions; using BizHawk.Client.EmuHawk.WinFormExtensions; +using BizHawk.Emulation.Common; namespace BizHawk.Client.EmuHawk { @@ -507,7 +508,7 @@ namespace BizHawk.Client.EmuHawk 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]; if (!state.SequenceEqual(greenzone.Value)) @@ -749,7 +750,7 @@ namespace BizHawk.Client.EmuHawk var newProject = CurrentTasMovie.ConvertToSavestateAnchoredMovie( index, - (byte[])Global.Emulator.SaveStateBinary().Clone()); + (byte[])((IStatable)Global.Emulator).SaveStateBinary().Clone()); GlobalWin.MainForm.PauseEmulator(); LoadProject(newProject.Filename); diff --git a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs index 52f80d1a8e..90f9ec75a7 100644 --- a/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs +++ b/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.cs @@ -5,6 +5,8 @@ using System.Linq; using System.Windows.Forms; using System.ComponentModel; +using BizHawk.Emulation.Common; + using BizHawk.Client.Common; using BizHawk.Client.Common.MovieConversionExtensions; @@ -313,7 +315,7 @@ namespace BizHawk.Client.EmuHawk private void LoadState(KeyValuePair 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) { diff --git a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj index 6dd1e917de..eab8b9f0b8 100644 --- a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj +++ b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj @@ -68,6 +68,7 @@ + diff --git a/BizHawk.Emulation.Common/Extensions.cs b/BizHawk.Emulation.Common/Extensions.cs index 077742ee89..9525e86da9 100644 --- a/BizHawk.Emulation.Common/Extensions.cs +++ b/BizHawk.Emulation.Common/Extensions.cs @@ -22,6 +22,11 @@ namespace BizHawk.Emulation.Common.IEmulatorExtensions return core is ISaveRam; } + public static bool HasSavestates(this IEmulator core) + { + return core is IStatable; + } + public static bool IsNull(this IEmulator core) { return core == null || core is NullEmulator; diff --git a/BizHawk.Emulation.Common/Interfaces/IEmulator.cs b/BizHawk.Emulation.Common/Interfaces/IEmulator.cs index a17faee739..d657cc637d 100644 --- a/BizHawk.Emulation.Common/Interfaces/IEmulator.cs +++ b/BizHawk.Emulation.Common/Interfaces/IEmulator.cs @@ -83,25 +83,6 @@ namespace BizHawk.Emulation.Common /// void ResetCounters(); - /// - /// Savestate handling methods - /// - /// - void SaveStateText(TextWriter writer); - void LoadStateText(TextReader reader); - void SaveStateBinary(BinaryWriter writer); - void LoadStateBinary(BinaryReader reader); - /// - /// save state binary to a byte buffer - /// - /// you may NOT modify this. if you call SaveStateBinary() again with the same core, the old data MAY be overwritten. - byte[] SaveStateBinary(); - - /// - /// true if the core would rather give a binary savestate than a text one. both must function regardless - /// - bool BinarySaveStatesPreferred { get; } - /// /// the corecomm module in use by this core. /// diff --git a/BizHawk.Emulation.Common/Interfaces/IStatable.cs b/BizHawk.Emulation.Common/Interfaces/IStatable.cs new file mode 100644 index 0000000000..30139a4987 --- /dev/null +++ b/BizHawk.Emulation.Common/Interfaces/IStatable.cs @@ -0,0 +1,27 @@ +using System.IO; + +namespace BizHawk.Emulation.Common +{ + /// + /// Savestate handling methods + /// + public interface IStatable : ICoreService, IEmulator + { + void SaveStateText(TextWriter writer); + void LoadStateText(TextReader reader); + + void SaveStateBinary(BinaryWriter writer); + void LoadStateBinary(BinaryReader reader); + + /// + /// save state binary to a byte buffer + /// + /// you may NOT modify this. if you call SaveStateBinary() again with the same core, the old data MAY be overwritten. + byte[] SaveStateBinary(); + + /// + /// true if the core would rather give a binary savestate than a text one. both must function regardless + /// + bool BinarySaveStatesPreferred { get; } + } +} diff --git a/BizHawk.Emulation.Cores/Calculator/TI83.cs b/BizHawk.Emulation.Cores/Calculator/TI83.cs index b08f5c312b..76c904436e 100644 --- a/BizHawk.Emulation.Cores/Calculator/TI83.cs +++ b/BizHawk.Emulation.Cores/Calculator/TI83.cs @@ -19,7 +19,7 @@ namespace BizHawk.Emulation.Cores.Calculators isPorted: false, isReleased: true )] - public partial class TI83 : IEmulator, IMemoryDomains, IDebuggable, ISettable + public partial class TI83 : IEmulator, IMemoryDomains, IStatable, IDebuggable, ISettable { //hardware private readonly Z80A cpu = new Z80A(); diff --git a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.cs b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.cs index f4ede6208b..ff6bc006b7 100644 --- a/BizHawk.Emulation.Cores/Computers/Commodore64/C64.cs +++ b/BizHawk.Emulation.Cores/Computers/Commodore64/C64.cs @@ -13,7 +13,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64 isPorted: false, isReleased: false )] - sealed public partial class C64 : IEmulator, IMemoryDomains + sealed public partial class C64 : IEmulator, IMemoryDomains, IStatable { // internal variables private bool _islag = true; diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs index cfc8d10b69..4e804341b7 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/2600/Atari2600.cs @@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600 isPorted: false, isReleased: true )] - public partial class Atari2600 : IEmulator, IMemoryDomains, IDebuggable, ISettable + public partial class Atari2600 : IEmulator, IMemoryDomains, IStatable, IDebuggable, ISettable { private readonly GameInfo _game; private bool _islag = true; diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.cs b/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.cs index 593a1eabd4..fb089b9d06 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.cs @@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari7800 portedVersion: "v1.5", portedUrl: "http://emu7800.sourceforge.net/" )] - public partial class Atari7800 : IEmulator, IMemoryDomains, ISaveRam, IDebuggable + public partial class Atari7800 : IEmulator, IMemoryDomains, ISaveRam, IDebuggable, IStatable { // TODO: // some things don't work when you try to plug in a 2600 game diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs b/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs index f5972fbd6e..91de88a788 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.cs @@ -12,7 +12,7 @@ using Newtonsoft.Json; namespace BizHawk.Emulation.Cores.Atari.Lynx { [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; diff --git a/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.cs b/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.cs index f4c6b023d0..d24b16cdbb 100644 --- a/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.cs +++ b/BizHawk.Emulation.Cores/Consoles/Intellivision/Intellivision.cs @@ -159,38 +159,6 @@ namespace BizHawk.Emulation.Cores.Intellivision //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 void Dispose() diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/Meteor.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/Meteor.cs index ea15acabe0..41511a579b 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/Meteor.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/Meteor.cs @@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA isPorted: true, 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 GetCpuFlagsAndRegisters() { diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs index cdeee037eb..a6337caca6 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/VBANext.cs @@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA { [CoreAttributes("VBA-Next", "many authors", true, true, "cd508312a29ed8c29dacac1b11c2dce56c338a54", "https://github.com/libretro/vba-next")] public class VBANext : IEmulator, IVideoProvider, ISyncSoundProvider, - IGBAGPUViewable, IMemoryDomains, ISaveRam, IDebuggable, ISettable + IGBAGPUViewable, IMemoryDomains, ISaveRam, IStatable, IDebuggable, ISettable { IntPtr Core; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs index edb1ad8466..d6897ccc56 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.cs @@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy portedVersion: "SVN 344", portedUrl: "http://gambatte.sourceforge.net/" )] - public class Gameboy : IEmulator, IVideoProvider, ISyncSoundProvider, ISaveRam, + public class Gameboy : IEmulator, IVideoProvider, ISyncSoundProvider, ISaveRam, IStatable, IMemoryDomains, IDebuggable, ISettable { #region ALL SAVESTATEABLE STATE GOES HERE diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs index b009ecd632..ebcffd8f33 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.cs @@ -17,7 +17,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64 portedVersion: "2.0", 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 { private readonly N64Input _inputProvider; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs index 1a06c41858..2c4f74e492 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs @@ -17,7 +17,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES isPorted: false, isReleased: true )] - public partial class NES : IEmulator, IMemoryDomains, ISaveRam, IDebuggable, + public partial class NES : IEmulator, IMemoryDomains, ISaveRam, IDebuggable, IStatable, ISettable { static readonly bool USE_DATABASE = true; diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs index 6d500a3af6..4ac73ab807 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.cs @@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES portedVersion: "0.7.0", 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 { #region FPU precision diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs index 7a0230d25f..1a65fc9bba 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs @@ -29,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES portedVersion: "v87", portedUrl: "http://byuu.org/" )] - public unsafe class LibsnesCore : IEmulator, IVideoProvider, IMemoryDomains, ISaveRam, + public unsafe class LibsnesCore : IEmulator, IVideoProvider, IMemoryDomains, ISaveRam, IStatable, IDebuggable, ISettable { public LibsnesCore(GameInfo game, byte[] romData, bool deterministicEmulation, byte[] xmlData, CoreComm comm, object Settings, object SyncSettings) diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES9X/Snes9x.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES9X/Snes9x.cs index c456d1bc69..ec374c9615 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES9X/Snes9x.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES9X/Snes9x.cs @@ -61,33 +61,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X public string BoardName { get { return null; } } 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 private int[] _vbuff = new int[512 * 480]; diff --git a/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.cs b/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.cs index aa345183ad..b163704bf7 100644 --- a/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.cs +++ b/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.cs @@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Cores.PCEngine isPorted: false, isReleased: true )] - public sealed partial class PCEngine : IEmulator, IMemoryDomains, ISaveRam, + public sealed partial class PCEngine : IEmulator, IMemoryDomains, ISaveRam, IStatable, IDebuggable, ISettable { // ROM diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Genesis.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Genesis.cs index 4f6b1fe5db..8a138b6347 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Genesis.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/Genesis/Genesis.cs @@ -21,7 +21,7 @@ namespace BizHawk.Emulation.Cores.Sega.Genesis isPorted: 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 bool lagged = true; diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Yabause.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Yabause.cs index 0615038238..89ecd7aadb 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Yabause.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Yabause.cs @@ -23,7 +23,7 @@ namespace BizHawk.Emulation.Cores.Sega.Saturn portedVersion: "9.12", portedUrl: "http://yabause.org" )] - public class Yabause : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam, + public class Yabause : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam, IStatable, ISettable { public static ControllerDefinition SaturnController = new ControllerDefinition diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.cs b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.cs index 02083cf5b8..dee05b60f8 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/gpgx/GPGX.cs @@ -24,7 +24,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx portedVersion: "r874", 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 { static GPGX AttachedCore = null; diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSP/PSP.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSP/PSP.cs index f808b966e1..8ca4bb99a4 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSP/PSP.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSP/PSP.cs @@ -43,7 +43,6 @@ namespace BizHawk.Emulation.Cores.Sony.PSP public IController Controller { get; set; } public bool DeterministicEmulation { get { return true; } } public string SystemId { get { return "PSP"; } } - public bool BinarySaveStatesPreferred { get { return true; } } public CoreComm CoreComm { get; private set; } 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 screenheight = 272; readonly int[] screenbuffer = new int[screenwidth * screenheight]; diff --git a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs index c0370c939c..94701af100 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs @@ -285,23 +285,6 @@ namespace BizHawk.Emulation.Cores.Sony.PSX [FeatureNotImplemented] 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 VirtualWidth { get; private set; } public int VirtualHeight { get { return BufferHeight; } } diff --git a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs index 31545e29b6..5fdd00768d 100644 --- a/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs +++ b/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.cs @@ -12,7 +12,7 @@ using System.Runtime.InteropServices; namespace BizHawk.Emulation.Cores.WonderSwan { [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 { #region Controller