From 10ed0872a49ec70cb8940b463d2928e945fd221d Mon Sep 17 00:00:00 2001 From: YoshiRulz Date: Fri, 12 Feb 2021 16:10:39 +1000 Subject: [PATCH] Add and use FirmwareID struct decided not to propogate to cores yet, left TODOs in Emulation.Common.Extensions --- src/BizHawk.Client.Common/CoreFileProvider.cs | 26 +++++++--------- .../fwmanager/FirmwareEventArgs.cs | 8 ++--- .../fwmanager/FirmwareManager.cs | 28 ++++++++--------- .../movie/MovieConversionExtensions.cs | 2 +- src/BizHawk.Client.EmuHawk/MainForm.cs | 2 +- .../config/FirmwaresConfig.cs | 25 +++++++--------- .../Database/FirmwareDatabase.cs | 6 ++-- .../Database/FirmwareID.cs | 30 +++++++++++++++++++ .../Database/FirmwareOption.cs | 8 ++--- .../Database/FirmwareRecord.cs | 6 +--- src/BizHawk.Emulation.Common/Extensions.cs | 15 +++++++++- .../Interfaces/ICoreFileProvider.cs | 7 ++--- .../Database/FirmwareDatabaseTests.cs | 2 +- 13 files changed, 93 insertions(+), 72 deletions(-) create mode 100644 src/BizHawk.Emulation.Common/Database/FirmwareID.cs diff --git a/src/BizHawk.Client.Common/CoreFileProvider.cs b/src/BizHawk.Client.Common/CoreFileProvider.cs index 12c08f5ce6..a101323d59 100644 --- a/src/BizHawk.Client.Common/CoreFileProvider.cs +++ b/src/BizHawk.Client.Common/CoreFileProvider.cs @@ -36,33 +36,29 @@ namespace BizHawk.Client.Common public string GetRetroSystemPath(IGameInfo game) => _pathEntries.RetroSystemAbsolutePath(game); - private void FirmwareWarn(string sysID, string firmwareID, bool required, string msg = null) + private void FirmwareWarn(FirmwareID id, bool required, string msg = null) { if (required) { - var fullMsg = $"Couldn't find required firmware \"{sysID}:{firmwareID}\". This is fatal{(msg != null ? $": {msg}" : ".")}"; + var fullMsg = $"Couldn't find required firmware \"{id.System}:{id.Firmware}\". This is fatal{(msg != null ? $": {msg}" : ".")}"; throw new MissingFirmwareException(fullMsg); } if (msg != null) { - var fullMsg = $"Couldn't find firmware \"{sysID}:{firmwareID}\". Will attempt to continue: {msg}"; + var fullMsg = $"Couldn't find firmware \"{id.System}:{id.Firmware}\". Will attempt to continue: {msg}"; _showWarning(fullMsg); } } - private byte[] GetFirmwareWithPath(string sysId, string firmwareId, bool required, string msg, out string path) + private byte[] GetFirmwareWithPath(FirmwareID id, bool required, string msg, out string path) { - var firmwarePath = _firmwareManager.Request( - _pathEntries, - _firmwareUserSpecifications, - sysId, - firmwareId); + var firmwarePath = _firmwareManager.Request(_pathEntries, _firmwareUserSpecifications, id); if (firmwarePath == null || !File.Exists(firmwarePath)) { path = null; - FirmwareWarn(sysId, firmwareId, required, msg); + FirmwareWarn(id, required, msg); return null; } @@ -75,19 +71,19 @@ namespace BizHawk.Client.Common catch (IOException) { path = null; - FirmwareWarn(sysId, firmwareId, required, msg); + FirmwareWarn(id, required, msg); return null; } } /// not found and is true - public byte[] GetFirmware(string sysId, string firmwareId, bool required, string msg = null) - => GetFirmwareWithPath(sysId, firmwareId, required, msg, out _); + public byte[] GetFirmware(FirmwareID id, bool required, string msg = null) + => GetFirmwareWithPath(id, required, msg, out _); /// not found and is true - public byte[] GetFirmwareWithGameInfo(string sysId, string firmwareId, bool required, out GameInfo gi, string msg = null) + public byte[] GetFirmwareWithGameInfo(FirmwareID id, bool required, out GameInfo gi, string msg = null) { - byte[] ret = GetFirmwareWithPath(sysId, firmwareId, required, msg, out var path); + var ret = GetFirmwareWithPath(id, required, msg, out var path); gi = ret != null && path != null ? Database.GetGameInfo(ret, path) : null; diff --git a/src/BizHawk.Client.Common/fwmanager/FirmwareEventArgs.cs b/src/BizHawk.Client.Common/fwmanager/FirmwareEventArgs.cs index 9b0fc9b252..f88549acee 100644 --- a/src/BizHawk.Client.Common/fwmanager/FirmwareEventArgs.cs +++ b/src/BizHawk.Client.Common/fwmanager/FirmwareEventArgs.cs @@ -1,13 +1,13 @@ +using BizHawk.Emulation.Common; + namespace BizHawk.Client.Common { public sealed class FirmwareEventArgs { - public string FirmwareId { get; set; } - public string Hash { get; set; } - public long Size { get; set; } + public FirmwareID ID { get; set; } - public string SystemId { get; set; } + public long Size { get; set; } } } diff --git a/src/BizHawk.Client.Common/fwmanager/FirmwareManager.cs b/src/BizHawk.Client.Common/fwmanager/FirmwareManager.cs index e3013aaf86..fdec3a1807 100644 --- a/src/BizHawk.Client.Common/fwmanager/FirmwareManager.cs +++ b/src/BizHawk.Client.Common/fwmanager/FirmwareManager.cs @@ -11,6 +11,8 @@ namespace BizHawk.Client.Common { public class FirmwareManager { + private static readonly FirmwareID NDS_FIRMWARE = new("NDS", "firmware"); + public List RecentlyServed { get; } = new List(); private readonly Dictionary _resolutionDictionary = new(); @@ -30,12 +32,12 @@ namespace BizHawk.Client.Common } // Requests the specified firmware. tries really hard to scan and resolve as necessary - public string Request(PathEntryCollection pathEntries, IDictionary userSpecifications, string sysId, string firmwareId) + public string Request(PathEntryCollection pathEntries, IDictionary userSpecifications, FirmwareID id) { var resolved = Resolve( pathEntries, userSpecifications, - FirmwareDatabase.FirmwareRecords.FirstOrDefault(fr => fr.FirmwareId == firmwareId && fr.SystemId == sysId)); + FirmwareDatabase.FirmwareRecords.FirstOrDefault(fr => fr.ID == id)); if (resolved == null) { return null; @@ -43,8 +45,7 @@ namespace BizHawk.Client.Common RecentlyServed.Add(new FirmwareEventArgs { - SystemId = sysId, - FirmwareId = firmwareId, + ID = id, Hash = resolved.Hash, Size = resolved.Size }); @@ -150,11 +151,8 @@ namespace BizHawk.Client.Common _resolutionDictionary.Remove(fr); // get all options for this firmware (in order) - var fr1 = fr; - var options = FirmwareDatabase.FirmwareOptions - .Where(fo => fo.SystemId == fr1.SystemId - && fo.FirmwareId == fr1.FirmwareId - && fo.IsAcceptableOrIdeal); + var id = fr.ID; + var options = FirmwareDatabase.FirmwareOptions.Where(fo => fo.ID == id && fo.IsAcceptableOrIdeal); // try each option foreach (var fo in options) @@ -182,7 +180,7 @@ namespace BizHawk.Client.Common foreach (var fr in FirmwareDatabase.FirmwareRecords) { // do we have a user specification for this firmware record? - if (userSpecifications.TryGetValue(fr.ConfigKey, out var userSpec)) + if (userSpecifications.TryGetValue(fr.ID.ConfigKey, out var userSpec)) { // flag it as user specified if (!_resolutionDictionary.TryGetValue(fr, out ResolutionInfo ri)) @@ -205,12 +203,10 @@ namespace BizHawk.Client.Common } // compute its hash - RealFirmwareFile rff; // NDS's firmware file contains user settings; these are over-written by sync settings, so we shouldn't allow them to impact the hash - if (fr.SystemId == "NDS" && fr.FirmwareId == "firmware") - rff = reader.Read(new FileInfo(Emulation.Cores.Consoles.Nintendo.NDS.MelonDS.CreateModifiedFirmware(userSpec))); - else - rff = reader.Read(fi); + var rff = reader.Read(fr.ID == NDS_FIRMWARE + ? new FileInfo(Emulation.Cores.Consoles.Nintendo.NDS.MelonDS.CreateModifiedFirmware(userSpec)) + : fi); ri.Size = fi.Length; ri.Hash = rff.Hash; @@ -220,7 +216,7 @@ namespace BizHawk.Client.Common ri.KnownFirmwareFile = ff; // if the known firmware file is for a different firmware, flag it so we can show a warning - if (FirmwareDatabase.FirmwareOptions.Any(fo => fo.Hash == rff.Hash && fo.ConfigKey != fr.ConfigKey)) + if (FirmwareDatabase.FirmwareOptions.Any(fo => fo.Hash == rff.Hash && fo.ID != fr.ID)) { ri.KnownMismatching = true; } diff --git a/src/BizHawk.Client.Common/movie/MovieConversionExtensions.cs b/src/BizHawk.Client.Common/movie/MovieConversionExtensions.cs index 855178307b..b37116ea99 100644 --- a/src/BizHawk.Client.Common/movie/MovieConversionExtensions.cs +++ b/src/BizHawk.Client.Common/movie/MovieConversionExtensions.cs @@ -239,7 +239,7 @@ namespace BizHawk.Client.Common { foreach (var firmware in firmwareManager.RecentlyServed) { - var key = $"{firmware.SystemId}_Firmware_{firmware.FirmwareId}"; + var key = $"{firmware.ID.System}_Firmware_{firmware.ID.Firmware}"; if (!movie.HeaderEntries.ContainsKey(key)) { diff --git a/src/BizHawk.Client.EmuHawk/MainForm.cs b/src/BizHawk.Client.EmuHawk/MainForm.cs index 3c0f4f17d5..d98a0aecc3 100644 --- a/src/BizHawk.Client.EmuHawk/MainForm.cs +++ b/src/BizHawk.Client.EmuHawk/MainForm.cs @@ -3854,7 +3854,7 @@ namespace BizHawk.Client.EmuHawk Console.WriteLine("Active Firmwares:"); foreach (var f in FirmwareManager.RecentlyServed) { - Console.WriteLine(" {0} : {1}", f.FirmwareId, f.Hash); + Console.WriteLine($" {f.ID} : {f.Hash}"); } } diff --git a/src/BizHawk.Client.EmuHawk/config/FirmwaresConfig.cs b/src/BizHawk.Client.EmuHawk/config/FirmwaresConfig.cs index 5910a806f2..0d9f522b8b 100644 --- a/src/BizHawk.Client.EmuHawk/config/FirmwaresConfig.cs +++ b/src/BizHawk.Client.EmuHawk/config/FirmwaresConfig.cs @@ -177,8 +177,8 @@ namespace BizHawk.Client.EmuHawk ImageIndex = IdUnsure, ToolTipText = null }; - lvi.SubItems.Add(fr.SystemId); - lvi.SubItems.Add(fr.FirmwareId); + lvi.SubItems.Add(fr.ID.System); + lvi.SubItems.Add(fr.ID.Firmware); lvi.SubItems.Add(fr.Descr); lvi.SubItems.Add(""); // resolved with lvi.SubItems.Add(""); // location @@ -189,15 +189,15 @@ namespace BizHawk.Client.EmuHawk lvFirmwares.Items.Add(lvi); // build the groups in the ListView as we go: - if (!groups.ContainsKey(fr.SystemId)) + if (!groups.ContainsKey(fr.ID.System)) { - if (!SystemGroupNames.TryGetValue(fr.SystemId, out var name)) + if (!SystemGroupNames.TryGetValue(fr.ID.System, out var name)) name = "FIX ME (FirmwaresConfig.cs)"; - lvFirmwares.Groups.Add(fr.SystemId, name); + lvFirmwares.Groups.Add(fr.ID.System, name); var lvg = lvFirmwares.Groups[lvFirmwares.Groups.Count - 1]; - groups[fr.SystemId] = lvg; + groups[fr.ID.System] = lvg; } - lvi.Group = groups[fr.SystemId]; + lvi.Group = groups[fr.ID.System]; } // now that we have some items in the ListView, we can size some columns to sensible widths @@ -496,7 +496,7 @@ namespace BizHawk.Client.EmuHawk } } - _firmwareUserSpecifications[fr.ConfigKey] = filePath; + _firmwareUserSpecifications[fr.ID.ConfigKey] = filePath; } } catch (Exception ex) @@ -515,7 +515,7 @@ namespace BizHawk.Client.EmuHawk foreach (ListViewItem lvi in lvFirmwares.SelectedItems) { var fr = (FirmwareRecord) lvi.Tag; - _firmwareUserSpecifications.Remove(fr.ConfigKey); + _firmwareUserSpecifications.Remove(fr.ID.ConfigKey); } DoScan(); @@ -527,16 +527,13 @@ namespace BizHawk.Client.EmuHawk var fr = (FirmwareRecord) lvi.Tag; // get all options for this firmware (in order) - var options = - from fo in FirmwareDatabase.FirmwareOptions - where fo.SystemId == fr.SystemId && fo.FirmwareId == fr.FirmwareId - select fo; + var options = FirmwareDatabase.FirmwareOptions.Where(fo => fo.ID == fr.ID); var fciDialog = new FirmwaresConfigInfo { lblFirmware = { - Text = $"{fr.SystemId} : {fr.FirmwareId} ({fr.Descr})" + Text = $"{fr.ID.System} : {fr.ID.Firmware} ({fr.Descr})" } }; diff --git a/src/BizHawk.Emulation.Common/Database/FirmwareDatabase.cs b/src/BizHawk.Emulation.Common/Database/FirmwareDatabase.cs index af3f052da1..b789848227 100644 --- a/src/BizHawk.Emulation.Common/Database/FirmwareDatabase.cs +++ b/src/BizHawk.Emulation.Common/Database/FirmwareDatabase.cs @@ -41,8 +41,7 @@ namespace BizHawk.Emulation.Common void Option(string systemId, string id, FirmwareFile ff, FirmwareOptionStatus status = FirmwareOptionStatus.Acceptable) => options.Add(new FirmwareOption { - SystemId = systemId, - FirmwareId = id, + ID = new(systemId, id), Hash = ff.Hash, Status = ff.Bad ? FirmwareOptionStatus.Bad : status, Size = ff.Size @@ -51,8 +50,7 @@ namespace BizHawk.Emulation.Common void Firmware(string systemId, string id, string desc) => records.Add(new FirmwareRecord { - SystemId = systemId, - FirmwareId = id, + ID = new(systemId, id), Descr = desc }); diff --git a/src/BizHawk.Emulation.Common/Database/FirmwareID.cs b/src/BizHawk.Emulation.Common/Database/FirmwareID.cs new file mode 100644 index 0000000000..e5acbc162e --- /dev/null +++ b/src/BizHawk.Emulation.Common/Database/FirmwareID.cs @@ -0,0 +1,30 @@ +#nullable enable + +namespace BizHawk.Emulation.Common +{ + public readonly struct FirmwareID + { + public static bool operator ==(FirmwareID a, FirmwareID b) => a.Firmware == b.Firmware && a.System == b.System; + + public static bool operator !=(FirmwareID a, FirmwareID b) => a.Firmware != b.Firmware || a.System != b.System; + + public string ConfigKey => $"{System}+{Firmware}"; + + public readonly string Firmware; + + public readonly string System; + + public FirmwareID(string system, string firmware) + { + System = system; + Firmware = firmware; + } + + public override bool Equals(object obj) => obj is FirmwareID other + && other.Firmware == Firmware && other.System == System; + + public override int GetHashCode() => (System, Firmware).GetHashCode(); + + public override string ToString() => ConfigKey; + } +} diff --git a/src/BizHawk.Emulation.Common/Database/FirmwareOption.cs b/src/BizHawk.Emulation.Common/Database/FirmwareOption.cs index 09428af620..6ba8daeeb9 100644 --- a/src/BizHawk.Emulation.Common/Database/FirmwareOption.cs +++ b/src/BizHawk.Emulation.Common/Database/FirmwareOption.cs @@ -2,18 +2,14 @@ namespace BizHawk.Emulation.Common { public sealed class FirmwareOption { - public string ConfigKey => $"{SystemId}+{FirmwareId}"; - - public string FirmwareId { get; set; } - public string Hash { get; set; } + public FirmwareID ID { get; set; } + public bool IsAcceptableOrIdeal => Status == FirmwareOptionStatus.Ideal || Status == FirmwareOptionStatus.Acceptable; public long Size { get; set; } public FirmwareOptionStatus Status { get; set; } - - public string SystemId { get; set; } } } diff --git a/src/BizHawk.Emulation.Common/Database/FirmwareRecord.cs b/src/BizHawk.Emulation.Common/Database/FirmwareRecord.cs index e78a9c6fbe..f4cdbd3aa3 100644 --- a/src/BizHawk.Emulation.Common/Database/FirmwareRecord.cs +++ b/src/BizHawk.Emulation.Common/Database/FirmwareRecord.cs @@ -2,12 +2,8 @@ namespace BizHawk.Emulation.Common { public sealed class FirmwareRecord { - public string ConfigKey => $"{SystemId}+{FirmwareId}"; - public string Descr { get; set; } - public string FirmwareId { get; set; } - - public string SystemId { get; set; } + public FirmwareID ID { get; set; } } } diff --git a/src/BizHawk.Emulation.Common/Extensions.cs b/src/BizHawk.Emulation.Common/Extensions.cs index 325a748585..51df723bbc 100644 --- a/src/BizHawk.Emulation.Common/Extensions.cs +++ b/src/BizHawk.Emulation.Common/Extensions.cs @@ -446,5 +446,18 @@ namespace BizHawk.Emulation.Common .AddAxis(string.Format(nameFormat, "Z"), rangeAll, neutralAll); public static AxisSpec With(this in AxisSpec spec, Range range, int neutral) => new AxisSpec(range, neutral, spec.IsReversed, spec.Constraint); + + /// Get a firmware as a byte array + /// the core systemID + /// the firmware id + /// if true, result is guaranteed to be valid; else null is possible if not found + /// message to show if fail to get + /// TODO inline (only change is wrapping strings in ctor, these IDs should probably be consts in each core's class) + public static byte[] GetFirmware(this ICoreFileProvider cfp, string sysId, string firmwareId, bool required, string msg = null) + => cfp.GetFirmware(new(system: sysId, firmware: firmwareId), required: required, msg: msg); + + /// TODO inline (only change is wrapping strings in ctor, these IDs should probably be consts in each core's class) + public static byte[] GetFirmwareWithGameInfo(this ICoreFileProvider cfp, string sysId, string firmwareId, bool required, out GameInfo gi, string msg = null) + => cfp.GetFirmwareWithGameInfo(new(system: sysId, firmware: firmwareId), required: required, out gi, msg: msg); } -} \ No newline at end of file +} diff --git a/src/BizHawk.Emulation.Common/Interfaces/ICoreFileProvider.cs b/src/BizHawk.Emulation.Common/Interfaces/ICoreFileProvider.cs index df081dae77..6fbfbe4e8d 100644 --- a/src/BizHawk.Emulation.Common/Interfaces/ICoreFileProvider.cs +++ b/src/BizHawk.Emulation.Common/Interfaces/ICoreFileProvider.cs @@ -23,12 +23,11 @@ /// /// Get a firmware as a byte array /// - /// the core systemID - /// the firmware id + /// the firmware id /// if true, result is guaranteed to be valid; else null is possible if not found /// message to show if fail to get - byte[] GetFirmware(string sysId, string firmwareId, bool required, string msg = null); + byte[] GetFirmware(FirmwareID id, bool required, string msg = null); - byte[] GetFirmwareWithGameInfo(string sysId, string firmwareId, bool required, out GameInfo gi, string msg = null); + byte[] GetFirmwareWithGameInfo(FirmwareID id, bool required, out GameInfo gi, string msg = null); } } diff --git a/src/BizHawk.Tests/Emulation.Common/Database/FirmwareDatabaseTests.cs b/src/BizHawk.Tests/Emulation.Common/Database/FirmwareDatabaseTests.cs index 6ddbdc290f..98e26a48a1 100644 --- a/src/BizHawk.Tests/Emulation.Common/Database/FirmwareDatabaseTests.cs +++ b/src/BizHawk.Tests/Emulation.Common/Database/FirmwareDatabaseTests.cs @@ -13,7 +13,7 @@ namespace BizHawk.Tests.Emulation.Common [TestMethod] public void CheckFilesInOptions() { - foreach (var fo in FirmwareDatabase.FirmwareOptions) Assert.IsTrue(FirmwareDatabase.FirmwareFilesByHash.ContainsKey(fo.Hash), $"option {fo.ConfigKey} references unknown file {fo.Hash}"); + foreach (var fo in FirmwareDatabase.FirmwareOptions) Assert.IsTrue(FirmwareDatabase.FirmwareFilesByHash.ContainsKey(fo.Hash), $"option {fo.ID} references unknown file {fo.Hash}"); } [TestMethod]