diff --git a/Assets/dll/melonDS.wbx.zst b/Assets/dll/melonDS.wbx.zst index aa442b4496..c854bbf4ea 100644 Binary files a/Assets/dll/melonDS.wbx.zst and b/Assets/dll/melonDS.wbx.zst differ diff --git a/Assets/dll/virtualjaguar.wbx.zst b/Assets/dll/virtualjaguar.wbx.zst index ad5f66ef33..b4af6d97b1 100644 Binary files a/Assets/dll/virtualjaguar.wbx.zst and b/Assets/dll/virtualjaguar.wbx.zst differ diff --git a/src/BizHawk.Client.EmuHawk/movie/RecordMovie.cs b/src/BizHawk.Client.EmuHawk/movie/RecordMovie.cs index cba67fe001..d1432f63f9 100644 --- a/src/BizHawk.Client.EmuHawk/movie/RecordMovie.cs +++ b/src/BizHawk.Client.EmuHawk/movie/RecordMovie.cs @@ -102,7 +102,7 @@ namespace BizHawk.Client.EmuHawk MaxDropDownItems = 32, Size = new(152, 21), }; - if (_emulator.HasSaveRam() && _emulator.AsSaveRam().CloneSaveRam() is not null) StartFromCombo.Items.Add(START_FROM_SAVERAM); + if (_emulator.HasSaveRam() && _emulator.AsSaveRam().CloneSaveRam(clearDirty: false) is not null) StartFromCombo.Items.Add(START_FROM_SAVERAM); if (_emulator.HasSavestates()) StartFromCombo.Items.Add(START_FROM_SAVESTATE); DefaultAuthorCheckBox = new() @@ -243,7 +243,7 @@ namespace BizHawk.Client.EmuHawk { var core = _emulator.AsSaveRam(); movieToRecord.StartsFromSaveRam = true; - movieToRecord.SaveRam = core.CloneSaveRam(); + movieToRecord.SaveRam = core.CloneSaveRam(clearDirty: false); } _mainForm.StartNewMovie(movieToRecord, true); diff --git a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs index 62e439239a..2d6e662b7f 100644 --- a/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs +++ b/src/BizHawk.Client.EmuHawk/tools/TAStudio/TAStudio.MenuItems.cs @@ -55,7 +55,7 @@ namespace BizHawk.Client.EmuHawk { if (AskSaveChanges()) { - var saveRam = SaveRamEmulator?.CloneSaveRam() ?? throw new Exception("No SaveRam"); + var saveRam = SaveRamEmulator?.CloneSaveRam(clearDirty: false) ?? throw new Exception("No SaveRam"); GoToFrame(TasView.AnyRowsSelected ? TasView.FirstSelectedRowIndex : 0); var newProject = CurrentTasMovie.ConvertToSaveRamAnchoredMovie(saveRam); MainForm.PauseEmulator(); diff --git a/src/BizHawk.Emulation.Common/Base Implementations/LinkedSaveRam.cs b/src/BizHawk.Emulation.Common/Base Implementations/LinkedSaveRam.cs index fd5da55402..cd2ea92225 100644 --- a/src/BizHawk.Emulation.Common/Base Implementations/LinkedSaveRam.cs +++ b/src/BizHawk.Emulation.Common/Base Implementations/LinkedSaveRam.cs @@ -31,13 +31,13 @@ namespace BizHawk.Emulation.Common return false; } - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { var linkedBuffers = new List(); int len = 0; for (int i = 0; i < _numCores; i++) { - linkedBuffers.Add(_linkedCores[i].AsSaveRam().CloneSaveRam() ?? Array.Empty()); + linkedBuffers.Add(_linkedCores[i].AsSaveRam().CloneSaveRam(clearDirty) ?? Array.Empty()); len += linkedBuffers[i].Length; } byte[] ret = new byte[len]; diff --git a/src/BizHawk.Emulation.Common/Interfaces/Services/ISaveRam.cs b/src/BizHawk.Emulation.Common/Interfaces/Services/ISaveRam.cs index 7fe10020de..d0fa8d67e8 100644 --- a/src/BizHawk.Emulation.Common/Interfaces/Services/ISaveRam.cs +++ b/src/BizHawk.Emulation.Common/Interfaces/Services/ISaveRam.cs @@ -14,7 +14,8 @@ /// Unfortunately, the core may think differently of a nonexisting (null) saveram vs a 0 size saveram. /// Frontend users of the ISaveRam should treat null as nonexisting (and thus not even write the file, so that the "does not exist" condition can be roundtripped and not confused with an empty file) /// - byte[]? CloneSaveRam(); + /// Whether the saveram should be considered in a clean state after this call for purposes of + byte[]? CloneSaveRam(bool clearDirty = true); /// /// store new SaveRAM to the emu core. the data should be the same size as the return from ReadSaveRam() @@ -22,12 +23,9 @@ void StoreSaveRam(byte[] data); /// - /// Gets a value indicating whether or not SaveRAM has been modified since the last save - /// TODO: This is not the best interface. What defines a "save"? I suppose a Clone(), right? at least specify that here. - /// Clone() should probably take an option that says whether to clear the dirty flag. - /// And anyway, cores might not know if they can even track a functional dirty flag -- we should convey that fact somehow - /// (reminder: do that with flags, so we don't have to change the interface 10000 times) - /// Dirty SaveRAM can in principle be determined by the frontend in that case, but it could possibly be too slow for the file menu dropdown or other things + /// Gets a value indicating whether or not SaveRAM has been modified since the last call to either or (when passing true). + /// Cores may choose to always return true or return true for any non-default saveram. + /// This value should be considered a hint more than an absolute truth. /// bool SaveRamModified { get; } } diff --git a/src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.ISaveRam.cs index 921d6b918a..7bd53d6ca4 100644 --- a/src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.ISaveRam.cs @@ -18,7 +18,7 @@ namespace BizHawk.Emulation.Cores.Arcades.MAME public bool SaveRamModified => _nvramFilenames.Count > 0; - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { if (_nvramFilenames.Count == 0) { diff --git a/src/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.ISaveRam.cs index f16ff1b59f..b686ccf80e 100644 --- a/src/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Computers/AppleII/AppleII.ISaveRam.cs @@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Computers.AppleII public bool SaveRamModified => true; - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { using var ms = new MemoryStream(); using var bw = new BinaryWriter(ms); diff --git a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Cartridge/Mapper0020.cs b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Cartridge/Mapper0020.cs index 57da9b0d11..469f1ddfc4 100644 --- a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Cartridge/Mapper0020.cs +++ b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Cartridge/Mapper0020.cs @@ -104,8 +104,6 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge if (_chipB.CheckDataDirty() || _deltaB == null) _deltaB = DeltaSerializer.GetDelta(_originalMediaB, _chipB.Data).ToArray(); - - _saveRamDirty = false; } protected override void SyncStateInternal(Serializer ser) @@ -274,7 +272,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge ); } - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { FlushSaveRam(); @@ -287,7 +285,7 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64.Cartridge writer.Write(_deltaB); writer.Flush(); - _saveRamDirty = false; + if (clearDirty) _saveRamDirty = false; return result.ToArray(); } diff --git a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.SaveRam.cs b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.SaveRam.cs index d06f4d5397..a34b18e2f4 100644 --- a/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.SaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Computers/Commodore64/Serial/Drive1541.SaveRam.cs @@ -39,7 +39,7 @@ public sealed partial class Drive1541 : ISaveRam public bool SaveRamModified { get; private set; } = false; - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { SaveDeltas(); @@ -56,7 +56,7 @@ public sealed partial class Drive1541 : ISaveRam } } - SaveRamModified = false; + if (clearDirty) SaveRamModified = false; return ms.ToArray(); } diff --git a/src/BizHawk.Emulation.Cores/Computers/MSX/MSX.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Computers/MSX/MSX.ISaveRam.cs index c628aa99bf..7b226140c1 100644 --- a/src/BizHawk.Emulation.Cores/Computers/MSX/MSX.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Computers/MSX/MSX.ISaveRam.cs @@ -4,7 +4,7 @@ namespace BizHawk.Emulation.Cores.Computers.MSX { public partial class MSX : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { return (byte[]) SaveRAM?.Clone(); } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.ISaveRam.cs index f8012db14d..9e8d938d52 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/A7800Hawk/A7800Hawk.ISaveRam.cs @@ -4,7 +4,7 @@ namespace BizHawk.Emulation.Cores.Atari.A7800Hawk { public partial class A7800Hawk : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { return (byte[])_hsram.Clone(); } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/jaguar/LibVirtualJaguar.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/jaguar/LibVirtualJaguar.cs index 6ba419c8e7..2bf6bd38fc 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Atari/jaguar/LibVirtualJaguar.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/jaguar/LibVirtualJaguar.cs @@ -97,7 +97,7 @@ namespace BizHawk.Emulation.Cores.Atari.Jaguar public abstract bool SaveRamIsDirty(); [BizImport(CC)] - public abstract void GetSaveRam(byte[] dst); + public abstract void GetSaveRam(byte[] dst, bool clearDirty); [BizImport(CC)] public abstract void PutSaveRam(byte[] src); diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/jaguar/VirtualJaguar.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/jaguar/VirtualJaguar.ISaveRam.cs index 1f3ae2d321..3992a453c1 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Atari/jaguar/VirtualJaguar.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/jaguar/VirtualJaguar.ISaveRam.cs @@ -8,7 +8,7 @@ namespace BizHawk.Emulation.Cores.Atari.Jaguar public new bool SaveRamModified => _saveRamSize > 0 && _core.SaveRamIsDirty(); - public new byte[] CloneSaveRam() + public new byte[] CloneSaveRam(bool clearDirty) { if (_saveRamSize == 0) { @@ -16,7 +16,7 @@ namespace BizHawk.Emulation.Cores.Atari.Jaguar } byte[] ret = new byte[_saveRamSize]; - _core.GetSaveRam(ret); + _core.GetSaveRam(ret, clearDirty); return ret; } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.ISaveRam.cs index 7cd0eb0874..086e37f98d 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Atari/lynx/Lynx.ISaveRam.cs @@ -6,7 +6,7 @@ namespace BizHawk.Emulation.Cores.Atari.Lynx { public partial class Lynx : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { if (!LibLynx.GetSaveRamPtr(Core, out var size, out var data)) { diff --git a/src/BizHawk.Emulation.Cores/Consoles/GCE/Vectrex/VectrexHawk.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/GCE/Vectrex/VectrexHawk.ISaveRam.cs index aec0223973..c4b7eace2a 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/GCE/Vectrex/VectrexHawk.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/GCE/Vectrex/VectrexHawk.ISaveRam.cs @@ -4,7 +4,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Vectrex { public partial class VectrexHawk : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { return null; } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ISaveRam.cs index 64e2c88709..4950fc6678 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Magnavox/Odyssey2/O2Hawk.ISaveRam.cs @@ -4,7 +4,7 @@ namespace BizHawk.Emulation.Cores.Consoles.O2Hawk { public partial class O2Hawk : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { return (byte[])cart_RAM?.Clone(); } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.ISaveRam.cs index 4e2a3010d2..54fc08a59f 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/BSNES/BsnesCore.ISaveRam.cs @@ -9,10 +9,9 @@ namespace BizHawk.Emulation.Cores.Nintendo.BSNES private IntPtr _saveRam; private int _saveRamSize; - // yeah this is not the best. this will basically always return true as long as the saveRam exists. public bool SaveRamModified => _saveRamSize != 0; - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { if (_saveRamSize == 0) return null; diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.ISaveRam.cs index 04f8e6ffd4..76afb36a47 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/MGBAHawk.ISaveRam.cs @@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA { private readonly byte[] _saveScratch = new byte[262144]; - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { int len = LibmGBA.BizGetSaveRam(Core, _saveScratch, _saveScratch.Length); if (len == _saveScratch.Length) diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.ISaveRam.cs index 1d7bbdfb69..9843e303d1 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawk/GBHawk.ISaveRam.cs @@ -4,7 +4,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawk { public partial class GBHawk : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { return (byte[])cart_RAM?.Clone(); } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs index e10568c579..f5e69eb708 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink/GBHawkLink.ISaveRam.cs @@ -4,7 +4,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink { public partial class GBHawkLink : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { if (L.cart_RAM != null || R.cart_RAM != null) { diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.ISaveRam.cs index 841fb59c55..b4241b4730 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink3x/GBHawkLink3x.ISaveRam.cs @@ -4,7 +4,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink3x { public partial class GBHawkLink3x : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { if (L.cart_RAM != null || C.cart_RAM != null || R.cart_RAM != null) { diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.ISaveRam.cs index 3c3195cf24..e6fbe4a945 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/GBHawkLink4x/GBHawkLink4x.ISaveRam.cs @@ -4,7 +4,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBHawkLink4x { public partial class GBHawkLink4x : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { if (A.cart_RAM != null || B.cart_RAM != null || C.cart_RAM != null || D.cart_RAM != null) { diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISaveRam.cs index 476e388e0c..213ccd0d9d 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/Gameboy/Gambatte.ISaveRam.cs @@ -7,7 +7,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy // need to wire more stuff into the core to actually know this public bool SaveRamModified => LibGambatte.gambatte_getsavedatalength(GambatteState) != 0; - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { var length = LibGambatte.gambatte_getsavedatalength(GambatteState); diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.ISaveRam.cs index 347dc9e819..974f913376 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/N64/N64.ISaveRam.cs @@ -4,7 +4,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64 { public partial class N64 : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { return api.SaveSaveram(); } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/LibMelonDS.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/LibMelonDS.cs index 0961d43d33..0ae3edad6d 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/LibMelonDS.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/LibMelonDS.cs @@ -142,7 +142,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public abstract void PutSaveRam(IntPtr console, byte[] data, uint len); [BizImport(CC)] - public abstract void GetSaveRam(IntPtr console, byte[] data); + public abstract void GetSaveRam(IntPtr console, byte[] data, bool clearDirty); [BizImport(CC)] public abstract int GetSaveRamLength(IntPtr console); diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISaveRam.cs index 45b5d82d75..0364b53905 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NDS/MelonDS.ISaveRam.cs @@ -9,7 +9,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS public new bool SaveRamModified => IsDSiWare ? DSiWareSaveLength != 0 : _core.SaveRamIsDirty(); - public new byte[] CloneSaveRam() + public new byte[] CloneSaveRam(bool clearDirty) { if (IsDSiWare) { @@ -43,7 +43,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS if (length > 0) { var ret = new byte[length]; - _core.GetSaveRam(_console, ret); + _core.GetSaveRam(_console, ret, clearDirty); return ret; } @@ -73,4 +73,4 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.NDS } } } -} \ No newline at end of file +} diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ISaveRam.cs index 271046e524..67a9563a02 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.ISaveRam.cs @@ -15,7 +15,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES } } - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { if (Board is FDS fds) { diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.ISaveRam.cs index d312ca8456..57cb38fabe 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/QuickNES/QuickNES.ISaveRam.cs @@ -4,7 +4,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES { public partial class QuickNES : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { LibQuickNES.ThrowStringError(QN.qn_battery_ram_save(Context, _saveRamBuff, _saveRamBuff.Length)); return (byte[])_saveRamBuff.Clone(); diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.ISaveRam.cs index 2e81c15923..bae5d8c2a6 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.ISaveRam.cs @@ -11,7 +11,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.CARTRIDGE_RAM) != 0 || Api.QUERY_get_memory_size(LibsnesApi.SNES_MEMORY.SGB_CARTRAM) != 0; - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { using (Api.EnterExit()) { diff --git a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.ISaveRam.cs index dad1b2c930..c1d2c36954 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Nintendo/SameBoy/SameBoy.ISaveRam.cs @@ -6,7 +6,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy { public bool SaveRamModified => LibSameboy.sameboy_sramlen(SameboyState) != 0; - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { int length = LibSameboy.sameboy_sramlen(SameboyState); diff --git a/src/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.ISaveRam.cs index 4fd573749a..0dd85e1a64 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/PC Engine/PCEngine.ISaveRam.cs @@ -6,8 +6,9 @@ namespace BizHawk.Emulation.Cores.PCEngine { public bool SaveRamModified { get; private set; } - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { + if (clearDirty) SaveRamModified = false; return (byte[]) BRAM?.Clone(); } @@ -17,6 +18,8 @@ namespace BizHawk.Emulation.Cores.PCEngine { Array.Copy(data, BRAM, data.Length); } + + SaveRamModified = false; } } } diff --git a/src/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeoPort.cs b/src/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeoPort.cs index 8c4ef0d0d7..87975014f8 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeoPort.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/SNK/NeoGeoPort.cs @@ -51,7 +51,7 @@ namespace BizHawk.Emulation.Cores.Consoles.SNK } } - public new byte[] CloneSaveRam() + public new byte[] CloneSaveRam(bool clearDirty) { _exe.AddTransientFile(new byte[0], "SAV:flash"); diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sega/GGHawkLink/GGHawkLink.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Sega/GGHawkLink/GGHawkLink.ISaveRam.cs index dc6c7904d1..30967d7797 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Sega/GGHawkLink/GGHawkLink.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Sega/GGHawkLink/GGHawkLink.ISaveRam.cs @@ -4,7 +4,7 @@ namespace BizHawk.Emulation.Cores.Sega.GGHawkLink { public partial class GGHawkLink : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { if ((L.SaveRAM != null) || (R.SaveRAM != null)) { diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISaveRam.cs index 62b011f378..936a037a54 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Sega/SMS/SMS.ISaveRam.cs @@ -4,8 +4,9 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem { public partial class SMS : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { + if (clearDirty) SaveRamModified = false; return (byte[]) SaveRAM?.Clone(); } @@ -15,6 +16,8 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem { Array.Copy(data, SaveRAM, data.Length); } + + SaveRamModified = false; } public bool SaveRamModified { get; private set; } diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Saturnus.cs b/src/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Saturnus.cs index b96be5e132..b8ddca7175 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Saturnus.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Saturnus.cs @@ -118,7 +118,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.Saturn public new bool SaveRamModified => true; - public new byte[] CloneSaveRam() + public new byte[] CloneSaveRam(bool clearDirty) { var data = new byte[_saturnus.GetSaveRamLength()]; _saturnus.GetSaveRam(data); diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISaveRam.cs index 7107a7d9b6..37ad060240 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Sega/gpgx64/GPGX.ISaveRam.cs @@ -7,7 +7,7 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx { public partial class GPGX : ISaveRam { - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { var size = 0; var area = Core.gpgx_get_sram(ref size); diff --git a/src/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs b/src/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs index b144601fe0..218c85610f 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/Sony/PSX/Octoshock.cs @@ -922,7 +922,7 @@ namespace BizHawk.Emulation.Cores.Sony.PSX throw new InvalidOperationException("Async mode is not supported."); } - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { var cfg = _SyncSettings.FIOConfig.ToLogical(); int nMemcards = cfg.NumMemcards; diff --git a/src/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.ISaveRam.cs index b44c001a16..e338da7986 100644 --- a/src/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Consoles/WonderSwan/WonderSwan.ISaveRam.cs @@ -11,7 +11,7 @@ namespace BizHawk.Emulation.Cores.WonderSwan _saveramBuff = new byte[BizSwan.bizswan_saveramsize(Core)]; } - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { if (!BizSwan.bizswan_saveramsave(Core, _saveramBuff, _saveramBuff.Length)) { diff --git a/src/BizHawk.Emulation.Cores/Libretro/Libretro.ISaveRam.cs b/src/BizHawk.Emulation.Cores/Libretro/Libretro.ISaveRam.cs index 52e9a22125..06d03f776f 100644 --- a/src/BizHawk.Emulation.Cores/Libretro/Libretro.ISaveRam.cs +++ b/src/BizHawk.Emulation.Cores/Libretro/Libretro.ISaveRam.cs @@ -12,7 +12,7 @@ namespace BizHawk.Emulation.Cores.Libretro public bool SaveRamModified => _saveramSize > 0; - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { if (_saveramSize > 0) { diff --git a/src/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs b/src/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs index 257f55e9e3..9cbc2981b5 100644 --- a/src/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs +++ b/src/BizHawk.Emulation.Cores/Waterbox/WaterboxCore.cs @@ -158,7 +158,7 @@ namespace BizHawk.Emulation.Cores.Waterbox } } - public byte[] CloneSaveRam() + public byte[] CloneSaveRam(bool clearDirty) { if (_saveramSize == 0) return null; diff --git a/waterbox/melon/BizPlatform/BizSaveManager.cpp b/waterbox/melon/BizPlatform/BizSaveManager.cpp index 2425d69751..e69bcaab08 100644 --- a/waterbox/melon/BizPlatform/BizSaveManager.cpp +++ b/waterbox/melon/BizPlatform/BizSaveManager.cpp @@ -33,7 +33,7 @@ ECL_EXPORT void PutSaveRam(melonDS::NDS* nds, u8* data, u32 len) } } -ECL_EXPORT void GetSaveRam(melonDS::NDS* nds, u8* data) +ECL_EXPORT void GetSaveRam(melonDS::NDS* nds, u8* data, bool clearDirty) { const u32 ndsSaveLen = nds->GetNDSSaveLength(); const u32 gbaSaveLen = nds->GetGBASaveLength(); @@ -41,13 +41,13 @@ ECL_EXPORT void GetSaveRam(melonDS::NDS* nds, u8* data) if (ndsSaveLen) { memcpy(data, nds->GetNDSSave(), ndsSaveLen); - NdsSaveRamIsDirty = false; + if (clearDirty) NdsSaveRamIsDirty = false; } if (gbaSaveLen) { memcpy(data + ndsSaveLen, nds->GetGBASave(), gbaSaveLen); - GbaSaveRamIsDirty = false; + if (clearDirty) GbaSaveRamIsDirty = false; } } @@ -108,7 +108,7 @@ ECL_EXPORT void DSiWareSavsLength(melonDS::DSi* dsi, u32 titleId, u32* publicSav // TODO - I don't like this approach with NAND // Perhaps instead it would be better to use FileFlush to write to disk -// (guarded by frontend determinism switch, of course) +// (guarded by frontend determinism switch, of course) ECL_EXPORT u32 GetNANDSize(melonDS::DSi* dsi) { diff --git a/waterbox/virtualjaguar/BizInterface.cpp b/waterbox/virtualjaguar/BizInterface.cpp index 5d73b4c58a..40d3d3e9c4 100644 --- a/waterbox/virtualjaguar/BizInterface.cpp +++ b/waterbox/virtualjaguar/BizInterface.cpp @@ -107,17 +107,17 @@ ECL_EXPORT bool SaveRamIsDirty() return IsMemTrack() ? mtDirty : eeprom_dirty; } -ECL_EXPORT void GetSaveRam(u8* dst) +ECL_EXPORT void GetSaveRam(u8* dst, bool clearDirty) { if (IsMemTrack()) { memcpy(dst, mtMem, sizeof(mtMem)); - mtDirty = false; + if (clearDirty) mtDirty = false; } else { memcpy(dst, eeprom_ram, sizeof(eeprom_ram)); - eeprom_dirty = false; + if (clearDirty) eeprom_dirty = false; } }