Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,6 @@ public static ITasMovie ConvertToSaveRamAnchoredMovie(this ITasMovie old, byte[]

foreach (var (k, v) in old.HeaderEntries) tas.HeaderEntries[k] = v;

tas.StartsFromSaveRam = true;
tas.SyncSettingsJson = old.SyncSettingsJson;

foreach (string comment in old.Comments)
Expand Down
21 changes: 1 addition & 20 deletions src/BizHawk.Client.Common/movie/bk2/Bk2Movie.HeaderApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -51,26 +51,7 @@ public virtual bool StartsFromSavestate
}
}

public bool StartsFromSaveRam
{
// ReSharper disable SimplifyConditionalTernaryExpression
get => Header.TryGetValue(HeaderKeys.StartsFromSaveram, out var s) ? bool.Parse(s) : false;
// ReSharper restore SimplifyConditionalTernaryExpression
set
{
if (value)
{
if (!Header.ContainsKey(HeaderKeys.StartsFromSaveram))
{
Header.Add(HeaderKeys.StartsFromSaveram, "True");
}
}
else
{
Header.Remove(HeaderKeys.StartsFromSaveram);
}
}
}
public bool StartsFromSaveRam => SaveRam != null;

public override string GameName
{
Expand Down
2 changes: 1 addition & 1 deletion src/BizHawk.Client.Common/movie/interfaces/IMovie.cs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public interface IMovie : IBasicMovieInfo
byte[] SaveRam { get; set; }

bool StartsFromSavestate { get; set; }
bool StartsFromSaveRam { get; set; }
bool StartsFromSaveRam { get; }

string LogKey { get; set; }

Expand Down
46 changes: 14 additions & 32 deletions src/BizHawk.Client.EmuHawk/MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,8 @@

using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores;
using BizHawk.Emulation.Cores.Computers.AppleII;
using BizHawk.Emulation.Cores.Computers.Commodore64;
using BizHawk.Emulation.Cores.Computers.DOS;
using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES;
using BizHawk.Emulation.Cores.Consoles.SNK;
using BizHawk.Emulation.Cores.Nintendo.GBA;
using BizHawk.Emulation.Cores.Nintendo.NES;
using BizHawk.Emulation.Cores.Nintendo.SNES;

Expand Down Expand Up @@ -1921,36 +1917,24 @@ private void LoadSaveRam()
return;
}

byte[] sram = null;
try
{
byte[] sram;

// some cores might not know how big the saveram ought to be, so just send it the whole file
if (Emulator is AppleII or C64 or DOSBox or MGBAHawk or NeoGeoPort or NES { BoardName: "FDS" })
{
sram = File.ReadAllBytes(saveramToLoad.FullName);
}
else
{
var oldRam = Emulator.AsSaveRam().CloneSaveRam();
if (oldRam is null)
{
// we have a SaveRAM file, but the current core does not have save ram.
// just skip loading the saveram file in that case
return;
}

// why do we silently truncate\pad here instead of warning\erroring?
sram = new byte[oldRam.Length];
using var fs = saveramToLoad.OpenRead();
_ = fs.Read(sram, 0, sram.Length);
}
sram = File.ReadAllBytes(saveramToLoad.FullName);
}
catch (Exception e)
{
AddOnScreenMessage("An IO error occurred while loading Sram");
Console.Error.WriteLine(e);
}

Emulator.AsSaveRam().StoreSaveRam(sram);
try
{
if (sram != null) Emulator.AsSaveRam().StoreSaveRam(sram);
}
catch (IOException e)
catch (Exception e)
{
AddOnScreenMessage("An error occurred while loading Sram");
AddOnScreenMessage("The core threw an error while loading Sram");
Console.Error.WriteLine(e);
}
}
Expand All @@ -1976,9 +1960,7 @@ public bool FlushSaveRAM(bool autosave = false)
var backupPath = $"{path}.bak";
var backupFile = new FileInfo(backupPath);

var saveram = Emulator.AsSaveRam().CloneSaveRam();
if (saveram == null)
return true;
var saveram = Emulator.AsSaveRam().CloneSaveRam()!;

try
{
Expand Down
3 changes: 1 addition & 2 deletions src/BizHawk.Client.EmuHawk/movie/RecordMovie.cs
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public RecordMovie(
MaxDropDownItems = 32,
Size = new(152, 21),
};
if (_emulator.HasSaveRam() && _emulator.AsSaveRam().CloneSaveRam(clearDirty: false) is not null) StartFromCombo.Items.Add(START_FROM_SAVERAM);
if (_emulator.HasSaveRam()) StartFromCombo.Items.Add(START_FROM_SAVERAM);
if (_emulator.HasSavestates()) StartFromCombo.Items.Add(START_FROM_SAVESTATE);

DefaultAuthorCheckBox = new()
Expand Down Expand Up @@ -242,7 +242,6 @@ private void Ok_Click(object sender, EventArgs e)
else if (selectedStartFromValue is START_FROM_SAVERAM && _emulator.HasSaveRam())
{
var core = _emulator.AsSaveRam();
movieToRecord.StartsFromSaveRam = true;
movieToRecord.SaveRam = core.CloneSaveRam(clearDirty: false);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ private void StartANewProjectFromSaveRamMenuItem_Click(object sender, EventArgs
{
if (AskSaveChanges())
{
var saveRam = SaveRamEmulator?.CloneSaveRam(clearDirty: false) ?? throw new Exception("No SaveRam");
var saveRam = SaveRamEmulator?.CloneSaveRam(clearDirty: false) ?? throw new Exception("No SaveRam; this button should have been disabled.");
GoToFrame(TasView.AnyRowsSelected ? TasView.FirstSelectedRowIndex : 0);
var newProject = CurrentTasMovie.ConvertToSaveRamAnchoredMovie(saveRam);
MainForm.PauseEmulator();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ private bool LinkedSaveRamModified()
{
for (int i = 0; i < _numCores; i++)
{
if (_linkedCores[i].AsSaveRam().SaveRamModified)
if (_linkedCores[i].AsSaveRam()?.SaveRamModified == true)
{
return true;
}
Expand All @@ -37,7 +37,7 @@ public byte[] CloneSaveRam(bool clearDirty)
int len = 0;
for (int i = 0; i < _numCores; i++)
{
linkedBuffers.Add(_linkedCores[i].AsSaveRam().CloneSaveRam(clearDirty) ?? Array.Empty<byte>());
linkedBuffers.Add(_linkedCores[i].AsSaveRam()?.CloneSaveRam(clearDirty) ?? Array.Empty<byte>());
len += linkedBuffers[i].Length;
}
byte[] ret = new byte[len];
Expand All @@ -55,13 +55,15 @@ public void StoreSaveRam(byte[] data)
int pos = 0;
for (int i = 0; i < _numCores; i++)
{
var toCopy = _linkedCores[i].AsSaveRam().CloneSaveRam(); // wait CloneSaveRam is already a copy, why are we copying it again
if (toCopy is null) continue;
var b = new byte[toCopy.Length];
var numberBytesToCopy = _linkedCores[i].AsSaveRam()?.CloneSaveRam().Length;
if (numberBytesToCopy is null) continue;
var b = new byte[numberBytesToCopy.Value];
Buffer.BlockCopy(data, pos, b, 0, b.Length);
pos += b.Length;
_linkedCores[i].AsSaveRam().StoreSaveRam(b);
}

if (data.Length != pos) throw new InvalidOperationException("Incorrect sram size.");
}
}
}
8 changes: 3 additions & 5 deletions src/BizHawk.Emulation.Common/Interfaces/Services/ISaveRam.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,14 @@ public interface ISaveRam : IEmulatorService
{
/// <summary>
/// Returns a copy of the SaveRAM. Editing it won't do you any good unless you later call StoreSaveRam()
/// This IS allowed to return null.
/// 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)
/// </summary>
/// <param name="clearDirty">Whether the saveram should be considered in a clean state after this call for purposes of <see cref="SaveRamModified"/></param>
byte[]? CloneSaveRam(bool clearDirty = true);
byte[] CloneSaveRam(bool clearDirty = true);

/// <summary>
/// store new SaveRAM to the emu core. the data should be the same size as the return from ReadSaveRam()
/// Store new SaveRAM to the emu core.
/// </summary>
/// <exception cref="Exception">The core may throw an exception if the given data is invalid.</exception>
void StoreSaveRam(byte[] data);

/// <summary>
Expand Down
5 changes: 4 additions & 1 deletion src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.IEmulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ public partial class MAME : IEmulator
public string SystemId => VSystemID.Raw.Arcade;
public bool DeterministicEmulation { get; }
public int Frame { get; private set; }
public IEmulatorServiceProvider ServiceProvider { get; }

private BasicServiceProvider _serviceProvider;
public IEmulatorServiceProvider ServiceProvider => _serviceProvider;

public ControllerDefinition ControllerDefinition => MAMEController;

/// <summary>
Expand Down
4 changes: 2 additions & 2 deletions src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.ISaveRam.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public byte[] CloneSaveRam(bool clearDirty)
{
if (_nvramFilenames.Count == 0)
{
return null;
throw new InvalidOperationException("Core currently has no SRAM and should not be providing ISaveRam service.");
}

for (int i = 0; i < _nvramFilenames.Count; i++)
Expand Down Expand Up @@ -53,7 +53,7 @@ public void StoreSaveRam(byte[] data)
{
if (_nvramFilenames.Count == 0)
{
return;
throw new InvalidOperationException("Core currently has no SRAM and should not be providing ISaveRam service.");
}

using var ms = new MemoryStream(data, false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ private void InitMemoryDomains()
_memoryDomains.SystemBus = _memoryDomains[deviceName + " : System Bus"]!;
}

((BasicServiceProvider)ServiceProvider).Register<IMemoryDomains>(_memoryDomains);
_serviceProvider.Register<IMemoryDomains>(_memoryDomains);
}
}
}
8 changes: 6 additions & 2 deletions src/BizHawk.Emulation.Cores/Arcades/MAME/MAME.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,17 @@ public MAME(CoreLoadParameters<object, MAMESyncSettings> lp)
_gameFileName = Path.GetFileName(lp.Roms[0].RomPath.SubstringAfter('|')).ToLowerInvariant();
_syncSettings = lp.SyncSettings ?? new();

ServiceProvider = new BasicServiceProvider(this);
_serviceProvider = new BasicServiceProvider(this);
_serviceProvider.Unregister<ISaveRam>();
DeterministicEmulation = !_syncSettings.RTCSettings.UseRealTime || lp.DeterministicEmulationRequested;

_logCallback = MAMELogCallback;
_baseTimeCallback = MAMEBaseTimeCallback;
_inputPollCallback = InputCallbacks.Call;
_filenameCallback = name => _nvramFilenames.Add(name);
_filenameCallback = name => {
_nvramFilenames.Add(name);
_serviceProvider.Register<ISaveRam>(this);
};
_infoCallback = info =>
{
var text = info.Replace(". ", "\n").Replace("\n\n", "\n");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ public void StoreSaveRam(byte[] data)
var deltaBSize = reader.ReadInt32();
_deltaB = reader.ReadBytes(deltaBSize);

if (reader.BaseStream.Position != deltaASize + deltaBSize + 8) throw new InvalidOperationException("Incorrect sram size.");

DeltaSerializer.ApplyDelta(_originalMediaA, _chipA.Data, _deltaA);
DeltaSerializer.ApplyDelta(_originalMediaB, _chipB.Data, _deltaB);
_saveRamDirty = false;
Expand Down
3 changes: 2 additions & 1 deletion src/BizHawk.Emulation.Cores/Computers/MSX/MSX.IEmulator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ namespace BizHawk.Emulation.Cores.Computers.MSX
{
public partial class MSX : IEmulator, ISoundProvider, IVideoProvider
{
public IEmulatorServiceProvider ServiceProvider { get; }
private BasicServiceProvider _serviceProvider;
public IEmulatorServiceProvider ServiceProvider => _serviceProvider;

public ControllerDefinition ControllerDefinition => current_controller;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ private void SetupMemoryDomains()
SyncAllByteArrayDomains();

MemoryDomains = new MemoryDomainList(_byteArrayDomains.Values.Concat(domains).ToList());
(ServiceProvider as BasicServiceProvider).Register<IMemoryDomains>(MemoryDomains);
_serviceProvider.Register<IMemoryDomains>(MemoryDomains);

_memoryDomainsInit = true;
}
Expand Down
12 changes: 9 additions & 3 deletions src/BizHawk.Emulation.Cores/Computers/MSX/MSX.ISaveRam.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,26 @@ public partial class MSX : ISaveRam
{
public byte[] CloneSaveRam(bool clearDirty)
{
return (byte[]) SaveRAM?.Clone();
if (SaveRAM == null)
throw new InvalidOperationException("Core currently has no SRAM and should not be providing ISaveRam service.");
else
return (byte[]) SaveRAM.Clone();
}

public void StoreSaveRam(byte[] data)
{
if (SaveRAM != null)
if (SaveRAM == null)
throw new InvalidOperationException("Core currently has no SRAM and should not be providing ISaveRam service.");
else
{
if (data.Length != SaveRAM.Length) throw new InvalidOperationException("Incorrect sram size.");
Array.Copy(data, SaveRAM, data.Length);
}
}

public bool SaveRamModified { get; private set; }

public byte[] SaveRAM;
private byte[] SaveRAM;
private byte SaveRamBank;
}
}
10 changes: 5 additions & 5 deletions src/BizHawk.Emulation.Cores/Computers/MSX/MSX.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ public partial class MSX : IEmulator, IVideoProvider, ISoundProvider, ISaveRam,
[CoreConstructor(VSystemID.Raw.MSX)]
public MSX(CoreLoadParameters<MSXSettings, MSXSyncSettings> lp)
{
ServiceProvider = new BasicServiceProvider(this);
_serviceProvider = new BasicServiceProvider(this);
_serviceProvider.Unregister<ISaveRam>();
Settings = lp.Settings ?? new MSXSettings();
SyncSettings = lp.SyncSettings ?? new MSXSyncSettings();

Expand Down Expand Up @@ -141,7 +142,7 @@ public MSX(CoreLoadParameters<MSXSettings, MSXSyncSettings> lp)

blip.SetRates(3579545, 44100);

(ServiceProvider as BasicServiceProvider).Register<ISoundProvider>(this);
_serviceProvider.Register<ISoundProvider>(this);

SetupMemoryDomains();

Expand All @@ -156,9 +157,8 @@ public MSX(CoreLoadParameters<MSXSettings, MSXSyncSettings> lp)

Tracer = new TraceBuffer(newHeader.ToString());

var serviceProvider = ServiceProvider as BasicServiceProvider;
serviceProvider.Register<ITraceable>(Tracer);
serviceProvider.Register<IStatable>(new StateSerializer(SyncState));
_serviceProvider.Register<ITraceable>(Tracer);
_serviceProvider.Register<IStatable>(new StateSerializer(SyncState));

current_controller = SyncSettings.Contr_Setting == MSXSyncSettings.ContrType.Keyboard ? MSXControllerKB : MSXControllerJS;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public byte[] CloneSaveRam(bool clearDirty)

public void StoreSaveRam(byte[] data)
{
if (data.Length != _hsram.Length) throw new InvalidOperationException("Incorrect sram size.");
Buffer.BlockCopy(data, 0, _hsram, 0, data.Length);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ public partial class VirtualJaguar : ISaveRam
{
if (_saveRamSize == 0)
{
return null;
throw new InvalidOperationException("Core currently has no SRAM and should not be providing ISaveRam service.");
}

byte[] ret = new byte[_saveRamSize];
Expand All @@ -22,7 +22,9 @@ public partial class VirtualJaguar : ISaveRam

public new void StoreSaveRam(byte[] data)
{
if (_saveRamSize > 0)
if (_saveRamSize == 0)
throw new InvalidOperationException("Core currently has no SRAM and should not be providing ISaveRam service.");
else
{
if (data.Length != _saveRamSize)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ public VirtualJaguar(CoreLoadParameters<VirtualJaguarSettings, VirtualJaguarSync
}
}
}
if (_saveRamSize == 0)
_serviceProvider.Unregister<ISaveRam>();

_core.SetCdCallbacks(null, null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ private void SetupMemoryDomains()
{
mms.Add(new MemoryDomainIntPtr("Save RAM", MemoryDomain.Endian.Little, p, s, true, 2));
}
else
{
_serviceProvider.Unregister<ISaveRam>();
}

LibLynx.GetReadOnlyCartPtrs(Core, out var s0, out var p0, out var s1, out var p1);
if (s0 > 0 && p0 != IntPtr.Zero)
Expand Down
Loading
Loading