Break off saveram methods from IEmulator into a separate ISaveRam interface. Remove the setter for SaveRamModified (every single core was throwing an error on this, and no client code was using it). Remove these methods from cores that don't actually implement this interface

This commit is contained in:
adelikat 2014-11-30 15:22:08 +00:00
parent 9422f02fa2
commit 865795049b
29 changed files with 108 additions and 240 deletions

View File

@ -1411,70 +1411,76 @@ namespace BizHawk.Client.EmuHawk
private static void LoadSaveRam()
{
try // zero says: this is sort of sketchy... but this is no time for rearchitecting
if (Global.Emulator.HasSaveRam())
{
byte[] sram;
// GBA meteor core might not know how big the saveram ought to be, so just send it the whole file
// GBA vba-next core will try to eat anything, regardless of size
if (Global.Emulator is GBA || Global.Emulator is VBANext)
try // zero says: this is sort of sketchy... but this is no time for rearchitecting
{
sram = File.ReadAllBytes(PathManager.SaveRamPath(Global.Game));
}
else
{
var oldram = Global.Emulator.CloneSaveRam();
if (oldram == null)
{
// we're eating this one now. the possible negative consequence is that a user could lose
// their saveram and not know why
// MessageBox.Show("Error: tried to load saveram, but core would not accept it?");
return;
}
// why do we silently truncate\pad here instead of warning\erroring?
sram = new byte[oldram.Length];
using (var reader = new BinaryReader(
new FileStream(PathManager.SaveRamPath(Global.Game), FileMode.Open, FileAccess.Read)))
{
reader.Read(sram, 0, sram.Length);
}
}
byte[] sram;
Global.Emulator.StoreSaveRam(sram);
}
catch (IOException)
{
GlobalWin.OSD.AddMessage("An error occurred while loading Sram");
// GBA meteor core might not know how big the saveram ought to be, so just send it the whole file
// GBA vba-next core will try to eat anything, regardless of size
if (Global.Emulator is GBA || Global.Emulator is VBANext)
{
sram = File.ReadAllBytes(PathManager.SaveRamPath(Global.Game));
}
else
{
var oldram = (Global.Emulator as ISaveRam).CloneSaveRam();
if (oldram == null)
{
// we're eating this one now. the possible negative consequence is that a user could lose
// their saveram and not know why
// MessageBox.Show("Error: tried to load saveram, but core would not accept it?");
return;
}
// why do we silently truncate\pad here instead of warning\erroring?
sram = new byte[oldram.Length];
using (var reader = new BinaryReader(
new FileStream(PathManager.SaveRamPath(Global.Game), FileMode.Open, FileAccess.Read)))
{
reader.Read(sram, 0, sram.Length);
}
}
(Global.Emulator as ISaveRam).StoreSaveRam(sram);
}
catch (IOException)
{
GlobalWin.OSD.AddMessage("An error occurred while loading Sram");
}
}
}
private static void SaveRam()
{
var path = PathManager.SaveRamPath(Global.Game);
var f = new FileInfo(path);
if (f.Directory != null && f.Directory.Exists == false)
if (Global.Emulator.HasSaveRam())
{
f.Directory.Create();
}
// Make backup first
if (Global.Config.BackupSaveram && f.Exists)
{
var backup = path + ".bak";
var backupFile = new FileInfo(backup);
if (backupFile.Exists)
var path = PathManager.SaveRamPath(Global.Game);
var f = new FileInfo(path);
if (f.Directory != null && f.Directory.Exists == false)
{
backupFile.Delete();
f.Directory.Create();
}
f.CopyTo(backup);
// Make backup first
if (Global.Config.BackupSaveram && f.Exists)
{
var backup = path + ".bak";
var backupFile = new FileInfo(backup);
if (backupFile.Exists)
{
backupFile.Delete();
}
f.CopyTo(backup);
}
var writer = new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.Write));
var saveram = (Global.Emulator as ISaveRam).CloneSaveRam();
writer.Write(saveram, 0, saveram.Length);
writer.Close();
}
var writer = new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.Write));
var saveram = Global.Emulator.CloneSaveRam();
writer.Write(saveram, 0, saveram.Length);
writer.Close();
}
private void SelectSlot(int num)
@ -3425,7 +3431,7 @@ namespace BizHawk.Client.EmuHawk
GlobalWin.OSD.AddMessage("SRAM cleared.");
}
}
else if (Global.Emulator.SaveRamModified)
else if (Global.Emulator.HasSaveRam() && (Global.Emulator as ISaveRam).SaveRamModified)
{
SaveRam();
}

View File

@ -65,6 +65,7 @@
<Compile Include="Interfaces\IDebuggable.cs" />
<Compile Include="Interfaces\IEmulator.cs" />
<Compile Include="Interfaces\IMemoryDomains.cs" />
<Compile Include="Interfaces\ISaveRam.cs" />
<Compile Include="Interfaces\ISettable.cs" />
<Compile Include="Interfaces\ISoundProvider.cs" />
<Compile Include="Interfaces\ISyncSoundProvider.cs" />

View File

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

View File

@ -78,21 +78,6 @@ namespace BizHawk.Emulation.Common
/// </summary>
string BoardName { get; }
/// <summary>
/// return a copy of the saveram. editing it won't do you any good unless you later call StoreSaveRam()
/// </summary>
byte[] CloneSaveRam();
/// <summary>
/// store new saveram to the emu core. the data should be the same size as the return from ReadSaveRam()
/// </summary>
void StoreSaveRam(byte[] data);
/// <summary>
/// Whether or not Save ram has been modified since the last save
/// </summary>
bool SaveRamModified { get; set; }
/// <summary>
/// Resets the Frame and Lag counters, and any other similar counters a core might implement
/// </summary>

View File

@ -0,0 +1,20 @@
namespace BizHawk.Emulation.Common
{
public interface ISaveRam : IEmulator, ICoreService
{
/// <summary>
/// return a copy of the saveram. editing it won't do you any good unless you later call StoreSaveRam()
/// </summary>
byte[] CloneSaveRam();
/// <summary>
/// store new saveram to the emu core. the data should be the same size as the return from ReadSaveRam()
/// </summary>
void StoreSaveRam(byte[] data);
/// <summary>
/// Whether or not Save ram has been modified since the last save
/// </summary>
bool SaveRamModified { get; }
}
}

View File

@ -524,15 +524,6 @@ namespace BizHawk.Emulation.Cores.Calculators
public bool DeterministicEmulation { get { return true; } }
public byte[] CloneSaveRam() { return null; }
public void StoreSaveRam(byte[] data) { }
public bool SaveRamModified
{
get { return false; }
set { }
}
public bool BinarySaveStatesPreferred { get { return false; } }
public void SaveStateBinary(BinaryWriter bw) { SyncState(Serializer.CreateBinaryWriter(bw)); }
public void LoadStateBinary(BinaryReader br) { SyncState(Serializer.CreateBinaryReader(br)); }

View File

@ -17,23 +17,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
SyncState(new Serializer(reader));
}
public byte[] CloneSaveRam()
{
return null;
}
// TODO: when disk support is finished, set this flag according to if any writes to disk were done
public bool SaveRamModified
{
get
{
return false;
}
set
{
}
}
public void SaveStateBinary(BinaryWriter bw)
{
SyncState(new Serializer(bw));
@ -44,10 +27,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
SyncState(new Serializer(writer));
}
public void StoreSaveRam(byte[] data)
{
}
void SyncState(Serializer ser)
{
ser.BeginSection("core");

View File

@ -73,8 +73,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
public bool IsLagFrame { get { return _islag; } }
public bool SaveRamModified { get; set; }
public bool DeterministicEmulation { get; set; }
public bool BinarySaveStatesPreferred { get { return false; } }
@ -152,13 +150,6 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
ser.EndSection();
}
public byte[] CloneSaveRam()
{
return null;
}
public void StoreSaveRam(byte[] data) { }
public void SaveStateText(TextWriter writer)
{
SyncState(Serializer.CreateTextWriter(writer));

View File

@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari7800
portedVersion: "v1.5",
portedUrl: "http://emu7800.sourceforge.net/"
)]
public partial class Atari7800 : IEmulator, IMemoryDomains, IDebuggable
public partial class Atari7800 : IEmulator, IMemoryDomains, ISaveRam, IDebuggable
{
// TODO:
// some things don't work when you try to plug in a 2600 game
@ -73,6 +73,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari7800
private int _frame = 0;
#region saveram
public byte[] CloneSaveRam()
{
return (byte[])hsram.Clone();
@ -88,11 +89,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari7800
{
return GameInfo.MachineType == MachineType.A7800PAL || GameInfo.MachineType == MachineType.A7800NTSC;
}
set
{
throw new Exception("No one ever uses this, and it won't work with the way MainForm is set up.");
}
}
#endregion
public void Dispose()

View File

@ -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
public class Lynx : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam
{
IntPtr Core;
@ -312,10 +312,6 @@ namespace BizHawk.Emulation.Cores.Atari.Lynx
IntPtr unused2;
return LibLynx.GetSaveRamPtr(Core, out unused, out unused2);
}
set
{
throw new InvalidOperationException();
}
}
#endregion

View File

@ -170,10 +170,6 @@ namespace BizHawk.Emulation.Cores.ColecoVision
}
}
public byte[] CloneSaveRam() { return null; }
public void StoreSaveRam(byte[] data) { }
public bool SaveRamModified { get; set; }
public bool DeterministicEmulation { get { return true; } }
public bool BinarySaveStatesPreferred { get { return false; } }

View File

@ -152,27 +152,6 @@ namespace BizHawk.Emulation.Cores.Intellivision
public bool DeterministicEmulation { get { return true; } }
[FeatureNotImplemented]
public byte[] CloneSaveRam()
{
return null;
}
[FeatureNotImplemented]
public void StoreSaveRam(byte[] data)
{
}
public bool SaveRamModified
{
[FeatureNotImplemented]
get { return false; }
[FeatureNotImplemented]
set { }
}
public void ResetCounters()
{
Frame = 0;

View File

@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
isPorted: true,
isReleased: false
)]
public class GBA : IEmulator, IVideoProvider, ISyncSoundProvider, IGBAGPUViewable, IMemoryDomains, IDebuggable
public class GBA : IEmulator, IVideoProvider, ISyncSoundProvider, IGBAGPUViewable, IMemoryDomains, ISaveRam, IDebuggable
{
public IDictionary<string, int> GetCpuFlagsAndRegisters()
{
@ -140,8 +140,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
throw new ObjectDisposedException(this.GetType().ToString());
return LibMeteor.libmeteor_hassaveram();
}
set
{ }
}
#endregion

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")]
public class VBANext : IEmulator, IVideoProvider, ISyncSoundProvider,
IGBAGPUViewable, IMemoryDomains, IDebuggable, ISettable<object, VBANext.SyncSettings>
IGBAGPUViewable, IMemoryDomains, ISaveRam, IDebuggable, ISettable<object, VBANext.SyncSettings>
{
IntPtr Core;
@ -160,10 +160,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
{
return LibVBANext.SaveRamSize(Core) != 0;
}
set
{
throw new InvalidOperationException();
}
}
#endregion

View File

@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
portedVersion: "SVN 344",
portedUrl: "http://gambatte.sourceforge.net/"
)]
public class Gameboy : IEmulator, IVideoProvider, ISyncSoundProvider,
public class Gameboy : IEmulator, IVideoProvider, ISyncSoundProvider, ISaveRam,
IMemoryDomains, IDebuggable, ISettable<Gameboy.GambatteSettings, Gameboy.GambatteSyncSettings>
{
#region ALL SAVESTATEABLE STATE GOES HERE
@ -486,7 +486,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
else
return true; // need to wire more stuff into the core to actually know this
}
set { }
}
#endregion

View File

@ -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, IDebuggable,
public partial class N64 : IEmulator, IMemoryDomains, ISaveRam, IDebuggable,
ISettable<N64Settings, N64SyncSettings>
{
private readonly N64Input _inputProvider;
@ -301,7 +301,10 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
api.LoadSaveram(data);
}
public bool SaveRamModified { get { return true; } set { } }
public bool SaveRamModified
{
get { return true; }
}
#region Savestates

View File

@ -17,7 +17,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
isPorted: false,
isReleased: true
)]
public partial class NES : IEmulator, IMemoryDomains, IDebuggable,
public partial class NES : IEmulator, IMemoryDomains, ISaveRam, IDebuggable,
ISettable<NES.NESSettings, NES.NESSyncSettings>
{
static readonly bool USE_DATABASE = true;
@ -357,7 +357,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
if (board.SaveRam == null) return false;
return true;
}
set { }
}
private MemoryDomainList memoryDomains;

View File

@ -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,
public class QuickNES : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam,
IDebuggable, ISettable<QuickNES.QuickNESSettings, QuickNES.QuickNESSyncSettings>
{
#region FPU precision
@ -240,10 +240,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
{
return LibQuickNES.qn_has_battery_ram(Context);
}
set
{
throw new Exception();
}
}
#endregion

View File

@ -29,7 +29,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
portedVersion: "v87",
portedUrl: "http://byuu.org/"
)]
public unsafe class LibsnesCore : IEmulator, IVideoProvider, IMemoryDomains,
public unsafe class LibsnesCore : IEmulator, IVideoProvider, IMemoryDomains, ISaveRam,
IDebuggable, ISettable<LibsnesCore.SnesSettings, LibsnesCore.SnesSyncSettings>
{
public LibsnesCore(GameInfo game, byte[] romData, bool deterministicEmulation, byte[] xmlData, CoreComm comm, object Settings, object SyncSettings)
@ -712,7 +712,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
public bool SaveRamModified
{
set { }
get
{
return api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM) != 0;

View File

@ -61,35 +61,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES9X
public string BoardName { get { return null; } }
public CoreComm CoreComm { get; private set; }
#region saveram
[FeatureNotImplemented]
public byte[] CloneSaveRam()
{
return new byte[0];
}
[FeatureNotImplemented]
public void StoreSaveRam(byte[] data)
{
}
public bool SaveRamModified
{
get
{
return false;
}
[FeatureNotImplemented]
set
{
throw new NotImplementedException();
}
}
#endregion
#region savestates
public void SaveStateText(System.IO.TextWriter writer)

View File

@ -22,7 +22,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
isPorted: false,
isReleased: true
)]
public sealed partial class PCEngine : IEmulator, IMemoryDomains,
public sealed partial class PCEngine : IEmulator, IMemoryDomains, ISaveRam,
IDebuggable, ISettable<PCEngine.PCESettings, PCEngine.PCESyncSettings>
{
// ROM
@ -373,7 +373,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
Array.Copy(data, BRAM, data.Length);
}
public bool SaveRamModified { get; set; }
public bool SaveRamModified { get; private set; }
public bool BinarySaveStatesPreferred { get { return false; } }
public void SaveStateBinary(BinaryWriter bw) { SyncState(Serializer.CreateBinaryWriter(bw)); }

View File

@ -44,6 +44,6 @@ namespace BizHawk.Emulation.Cores.Sega.Genesis
public byte[] CloneSaveRam() { return (byte[])SaveRAM.Clone(); }
public void StoreSaveRam(byte[] data) { Array.Copy(data, SaveRAM, data.Length); }
public bool SaveRamModified { get; set; }
public bool SaveRamModified { get; private set; }
}
}

View File

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

View File

@ -27,7 +27,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
isPorted: false,
isReleased: true
)]
public sealed partial class SMS : IEmulator, IMemoryDomains,
public sealed partial class SMS : IEmulator, IMemoryDomains, ISaveRam,
IDebuggable, ISettable<SMS.SMSSettings, SMS.SMSSyncSettings>
{
// Constants
@ -57,7 +57,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
Array.Copy(data, SaveRAM, data.Length);
}
public bool SaveRamModified { get; set; }
public bool SaveRamModified { get; private set; }
// Machine resources
public Z80A Cpu;

View File

@ -23,7 +23,7 @@ namespace BizHawk.Emulation.Cores.Sega.Saturn
portedVersion: "9.12",
portedUrl: "http://yabause.org"
)]
public class Yabause : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains,
public class Yabause : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam,
ISettable<object, Yabause.SaturnSyncSettings>
{
public static ControllerDefinition SaturnController = new ControllerDefinition
@ -354,7 +354,6 @@ namespace BizHawk.Emulation.Cores.Sega.Saturn
else
return LibYabause.libyabause_saveramodified();
}
set { throw new InvalidOperationException("No you may not!"); }
}
#endregion

View File

@ -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,
public class GPGX : IEmulator, ISyncSoundProvider, IVideoProvider, IMemoryDomains, ISaveRam,
IDebuggable, ISettable<GPGX.GPGXSettings, GPGX.GPGXSyncSettings>
{
static GPGX AttachedCore = null;
@ -496,10 +496,6 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
return size > 0 && area != IntPtr.Zero;
}
}
set
{
throw new Exception();
}
}
#endregion

View File

@ -144,31 +144,6 @@ namespace BizHawk.Emulation.Cores.Sony.PSP
get { return true; }
}
[FeatureNotImplemented]
public byte[] CloneSaveRam()
{
return new byte[0];
}
[FeatureNotImplemented]
public void StoreSaveRam(byte[] data)
{
}
public bool SaveRamModified
{
[FeatureNotImplemented]
get
{
return false;
}
[FeatureNotImplemented]
set
{
}
}
[FeatureNotImplemented]
public void ResetCounters()
{

View File

@ -282,18 +282,9 @@ namespace BizHawk.Emulation.Cores.Sony.PSX
get { return false; }
}
[FeatureNotImplemented]
public byte[] CloneSaveRam() { return null; }
[FeatureNotImplemented]
public void StoreSaveRam(byte[] data) { }
[FeatureNotImplemented]
public bool DeterministicEmulation { get { return true; } }
[FeatureNotImplemented]
public bool SaveRamModified { get; set; }
[FeatureNotImplemented]
public void SaveStateText(TextWriter writer) { }

View File

@ -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,
public class WonderSwan : IEmulator, IVideoProvider, ISyncSoundProvider, IMemoryDomains, ISaveRam,
IDebuggable, ISettable<WonderSwan.Settings, WonderSwan.SyncSettings>
{
#region Controller
@ -200,7 +200,6 @@ namespace BizHawk.Emulation.Cores.WonderSwan
public bool SaveRamModified
{
get { return BizSwan.bizswan_saveramsize(Core) > 0; }
set { throw new InvalidOperationException(); }
}
#endregion