From 2a0217e06cab3bab17caf072f4dff9e8bf797380 Mon Sep 17 00:00:00 2001 From: goyuken Date: Mon, 9 Dec 2013 20:36:24 +0000 Subject: [PATCH] refactor a bit of firmware loading code to get some slop out of MainForm.LoadRom() --- .../BizHawk.Client.EmuHawk.csproj | 1 + BizHawk.Client.EmuHawk/MFEmuLoadHelper.cs | 65 +++++++++ BizHawk.Client.EmuHawk/MainForm.cs | 127 +++--------------- BizHawk.Common/Util.cs | 9 ++ .../BizHawk.Emulation.Common.csproj | 1 + .../Interfaces/IEmuLoadHelper.cs | 17 +++ .../Consoles/Atari/7800/Atari7800.cs | 7 +- .../Consoles/Nintendo/GBA/Meteor.cs | 8 +- .../Consoles/Nintendo/NES/NES.cs | 11 +- .../Consoles/Nintendo/SNES/LibsnesCore.cs | 9 +- .../Consoles/Sega/Saturn/Yabause.cs | 3 +- 11 files changed, 139 insertions(+), 119 deletions(-) create mode 100644 BizHawk.Client.EmuHawk/MFEmuLoadHelper.cs create mode 100644 BizHawk.Emulation.Common/Interfaces/IEmuLoadHelper.cs diff --git a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj index af407ce773..cb901f576a 100644 --- a/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj +++ b/BizHawk.Client.EmuHawk/BizHawk.Client.EmuHawk.csproj @@ -365,6 +365,7 @@ MainForm.cs Form + Form diff --git a/BizHawk.Client.EmuHawk/MFEmuLoadHelper.cs b/BizHawk.Client.EmuHawk/MFEmuLoadHelper.cs new file mode 100644 index 0000000000..dc33602955 --- /dev/null +++ b/BizHawk.Client.EmuHawk/MFEmuLoadHelper.cs @@ -0,0 +1,65 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Windows.Forms; +using BizHawk.Emulation.Common; +using BizHawk.Client.Common; +using System.IO; + +namespace BizHawk.Client.EmuHawk +{ + class MFEmuLoadHelper : IEmuLoadHelper + { + IWin32Window parent; + FirmwareManager firmware; + + public MFEmuLoadHelper(IWin32Window parent, FirmwareManager firmware) + { + this.parent = parent; + this.firmware = firmware; + } + + public void ShowMessage(string msg) + { + MessageBox.Show(parent, msg, "Load Warning"); + } + + public byte[] GetFirmware(string sysID, string firmwareID, bool required, string msg = null) + { + byte[] ret = null; + string path = firmware.Request(sysID, firmwareID); + if (path != null && File.Exists(path)) + { + try + { + ret = File.ReadAllBytes(path); + } + catch (IOException) + { + } + } + + if (ret == null) + { + + if (required) + { + string fullmsg = string.Format( + "Couldn't find required firmware \"{0}:{1}\". This is fatal{2}", sysID, firmwareID, msg != null ? ": " + msg : "."); + throw new Exception(fullmsg); + } + else + { + if (msg != null) + { + string fullmsg = string.Format( + "Couldn't find firmware \"{0}:{1}\". Will attempt to continue: {2}", sysID, firmwareID, msg); + ShowMessage(msg); + } + } + } + return ret; + } + } +} diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index ecb6186c43..9f5fdff84d 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -63,6 +63,7 @@ namespace BizHawk.Client.EmuHawk { GlobalWin.MainForm = this; Global.FirmwareManager = new FirmwareManager(); + EmuLoadHelper = new MFEmuLoadHelper(this, Global.FirmwareManager); Global.MovieSession = new MovieSession { Movie = new Movie(), @@ -918,6 +919,8 @@ namespace BizHawk.Client.EmuHawk private readonly SaveSlotManager _stateSlots = new SaveSlotManager(); private readonly Dictionary _snesPrepared = new Dictionary(); + private IEmuLoadHelper EmuLoadHelper; + //avi/wav state private IVideoWriter _currAviWriter; private ISoundProvider _aviSoundInput; @@ -3032,13 +3035,7 @@ namespace BizHawk.Client.EmuHawk { case "SAT": { - string biosPath = Global.FirmwareManager.Request("SAT", "J"); - if (!File.Exists(biosPath)) - { - MessageBox.Show("Saturn BIOS not found. Please check firmware configurations."); - return false; - } - var saturn = new Yabause(nextComm, disc, File.ReadAllBytes(biosPath), Global.Config.SaturnUseGL); + var saturn = new Yabause(nextComm, disc, EmuLoadHelper, Global.Config.SaturnUseGL); nextEmulator = saturn; SaturnSetPrefs(saturn); } @@ -3199,23 +3196,7 @@ namespace BizHawk.Client.EmuHawk break; case "NES": { - //TODO - move into nes core - var biosPath = nextComm.CoreFileProvider.PathFirmware("NES", "Bios_FDS"); - byte[] bios = null; - if (File.Exists(biosPath)) - { - bios = File.ReadAllBytes(biosPath); - // ines header + 24KB of garbage + actual bios + 8KB of garbage - if (bios.Length == 40976) - { - MessageBox.Show(this, "Your FDS BIOS is a bad dump. BizHawk will attempt to use it, but no guarantees! You should find a new one."); - var tmp = new byte[8192]; - Buffer.BlockCopy(bios, 16 + 8192 * 3, tmp, 0, 8192); - bios = tmp; - } - } - - var nes = new NES(nextComm, game, rom.FileData, bios, Global.MovieSession.Movie.Header.BoardProperties) + var nes = new NES(nextComm, game, rom.FileData, EmuLoadHelper, Global.MovieSession.Movie.Header.BoardProperties) { SoundOn = Global.Config.SoundEnabled, NTSC_FirstDrawLine = Global.Config.NTSC_NESTopLine, @@ -3264,40 +3245,23 @@ namespace BizHawk.Client.EmuHawk } else { - var sgbromPath = Global.FirmwareManager.Request("SNES", "Rom_SGB"); - byte[] sgbrom; try - { - if (File.Exists(sgbromPath)) - { - sgbrom = File.ReadAllBytes(sgbromPath); - } - else - { - MessageBox.Show("Couldn't open sgb.sfc from the configured SNES firmwares path, which is:\n\n" + sgbromPath + "\n\nPlease make sure it is available and try again.\n\nWe're going to disable SGB for now; please re-enable it when you've set up the file."); - Global.Config.GB_AsSGB = false; - game.System = "GB"; - goto RETRY; - } - } - catch (Exception) - { - // failed to load SGB bios. to avoid catch-22, disable SGB mode - Global.Config.GB_AsSGB = false; - throw; - } - if (sgbrom != null) { game.System = "SNES"; game.AddOption("SGB"); nextComm.SNES_ExePath = SNES_Prepare(Global.Config.SNESProfile); var snes = new LibsnesCore(nextComm); nextEmulator = snes; - game.FirmwareHash = Util.BytesToHexString(System.Security.Cryptography.SHA1.Create().ComputeHash(sgbrom)); - snes.Load(game, rom.FileData, sgbrom, deterministicemulation, null); + snes.Load(game, rom.FileData, EmuLoadHelper, deterministicemulation, null); + } + catch + { + // failed to load SGB bios. to avoid catch-22, disable SGB mode + EmuLoadHelper.ShowMessage("Failed to load a GB rom in SGB mode. Disabling SGB Mode."); + Global.Config.GB_AsSGB = false; + throw; } } - //} break; case "Coleco": var colbiosPath = Global.FirmwareManager.Request("Coleco", "Bios"); @@ -3332,56 +3296,9 @@ namespace BizHawk.Client.EmuHawk } break; case "A78": - var ntsc_biospath = Global.FirmwareManager.Request("A78", "Bios_NTSC"); - var pal_biospath = Global.FirmwareManager.Request("A78", "Bios_PAL"); - var hsbiospath = Global.FirmwareManager.Request("A78", "Bios_HSC"); - - var ntscfile = ntsc_biospath != null ? new FileInfo(ntsc_biospath) : null; - var palfile = pal_biospath != null ? new FileInfo(pal_biospath) : null; - var hsfile = hsbiospath != null ? new FileInfo(hsbiospath) : null; - - byte[] NTSC_BIOS7800 = null; - byte[] PAL_BIOS7800 = null; - byte[] HighScoreBIOS = null; - if (ntscfile == null || !ntscfile.Exists) - { - MessageBox.Show("Unable to find the required Atari 7800 BIOS file - \n" + ntsc_biospath + "\nIf the selected game requires it, it may crash", "Unable to load BIOS", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - else - { - NTSC_BIOS7800 = File.ReadAllBytes(ntsc_biospath); - } - - if (palfile == null || !palfile.Exists) - { - MessageBox.Show("Unable to find the required Atari 7800 BIOS file - \n" + pal_biospath + "\nIf the selected game requires it, it may crash", "Unable to load BIOS", MessageBoxButtons.OK, MessageBoxIcon.Error); - } - else - { - PAL_BIOS7800 = File.ReadAllBytes(pal_biospath); - } - - if (hsfile == null || !hsfile.Exists) - { - MessageBox.Show("Unable to find the required Atari 7800 BIOS file - \n" + hsbiospath + "\nIf the selected game requires it, it may crash", "Unable to load BIOS", MessageBoxButtons.OK, MessageBoxIcon.Error); - //throw new Exception(); - } - else - { - HighScoreBIOS = File.ReadAllBytes(hsbiospath); - } - var gamedbpath = Path.Combine(PathManager.GetExeDirectoryAbsolute(), "gamedb", "EMU7800.csv"); - try - { - var a78 = new Atari7800(nextComm, game, rom.RomData, NTSC_BIOS7800, PAL_BIOS7800, HighScoreBIOS, gamedbpath); - nextEmulator = a78; - } - catch (InvalidDataException ex) - { - MessageBox.Show(ex.Message, "Region specific bios missing", MessageBoxButtons.OK, MessageBoxIcon.Error); - return false; - } + var a78 = new Atari7800(nextComm, game, rom.RomData, EmuLoadHelper, gamedbpath); + nextEmulator = a78; break; case "C64": C64 c64 = new C64(nextComm, game, rom.RomData, rom.Extension); @@ -3391,21 +3308,9 @@ namespace BizHawk.Client.EmuHawk case "GBA": if (VersionInfo.INTERIM) { - var gbabiospath = Global.FirmwareManager.Request("GBA", "Bios"); - byte[] gbabios; - - if (File.Exists(gbabiospath)) - { - gbabios = File.ReadAllBytes(gbabiospath); - } - else - { - MessageBox.Show("Unable to find the required GBA BIOS file - \n" + gbabiospath, "Unable to load BIOS", MessageBoxButtons.OK, MessageBoxIcon.Error); - throw new Exception(); - } GBA gba = new GBA(nextComm); //var gba = new GarboDev.GbaManager(nextComm); - gba.Load(rom.RomData, gbabios); + gba.Load(rom.RomData, EmuLoadHelper); nextEmulator = gba; } break; diff --git a/BizHawk.Common/Util.cs b/BizHawk.Common/Util.cs index 97c4ffbaf1..6ecb5dbd8e 100644 --- a/BizHawk.Common/Util.cs +++ b/BizHawk.Common/Util.cs @@ -56,6 +56,15 @@ namespace BizHawk.Common } } + public static string Hash_SHA1(byte[] data) + { + using (var sha1 = System.Security.Cryptography.SHA1.Create()) + { + sha1.TransformFinalBlock(data, 0, data.Length); + return BytesToHexString(sha1.Hash); + } + } + public static bool IsPowerOfTwo(int x) { if (x == 0) return true; diff --git a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj index 98efb454a1..e4e312c207 100644 --- a/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj +++ b/BizHawk.Emulation.Common/BizHawk.Emulation.Common.csproj @@ -92,6 +92,7 @@ + diff --git a/BizHawk.Emulation.Common/Interfaces/IEmuLoadHelper.cs b/BizHawk.Emulation.Common/Interfaces/IEmuLoadHelper.cs new file mode 100644 index 0000000000..04909259a2 --- /dev/null +++ b/BizHawk.Emulation.Common/Interfaces/IEmuLoadHelper.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace BizHawk.Emulation.Common +{ + /// + /// some methods that an emulation core might want to have access to during its load sequence + /// + public interface IEmuLoadHelper + { + void ShowMessage(string msg); + + byte[] GetFirmware(string sysID, string firmwareID, bool required, string msg = null); + } +} diff --git a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.cs b/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.cs index 3a9f581657..ccd6c7e112 100644 --- a/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.cs +++ b/BizHawk.Emulation.Cores/Consoles/Atari/7800/Atari7800.cs @@ -177,10 +177,13 @@ namespace BizHawk.Emulation.Cores.Atari.Atari7800 } } - public Atari7800(CoreComm comm, GameInfo game, byte[] rom, byte[] ntsc_bios, byte[] pal_bios, byte[] highscoreBIOS, string GameDBfn) + public Atari7800(CoreComm comm, GameInfo game, byte[] rom, IEmuLoadHelper EmuLoadHelper, string GameDBfn) { CoreComm = comm; - + byte[] highscoreBIOS = EmuLoadHelper.GetFirmware("A78", "Bios_HSC", false, "Some functions may not work without the high score BIOS."); + byte[] pal_bios = EmuLoadHelper.GetFirmware("A78", "Bios_PAL", false, "The game will not run if the correct region BIOS is not available."); + byte[] ntsc_bios = EmuLoadHelper.GetFirmware("A78", "Bios_NTSC", false, "The game will not run if the correct region BIOS is not available."); + if (EMU7800.Win.GameProgramLibrary.EMU7800DB == null) { EMU7800.Win.GameProgramLibrary.EMU7800DB = new EMU7800.Win.GameProgramLibrary(new StreamReader(GameDBfn)); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/Meteor.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/Meteor.cs index f396dd81bc..c2d71d6778 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/Meteor.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/GBA/Meteor.cs @@ -43,12 +43,14 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA comm.NominalHeight = 160; } - public void Load(byte[] rom, byte[] bios) + public void Load(byte[] rom, IEmuLoadHelper EmuLoadHelper) { + byte[] bios = EmuLoadHelper.GetFirmware("GBA", "Bios", true, "GBA bios file is mandatory."); + if (bios.Length != 16384) - throw new Exception("GBA bios must be exactly 16384 bytes!"); + throw new InvalidDataException("GBA bios must be exactly 16384 bytes!"); if (rom.Length > 32 * 1024 * 1024) - throw new Exception("Rom is too big!"); + throw new InvalidDataException("Rom file is too big! No GBA game is larger than 32MB"); Init(); LibMeteor.libmeteor_hardreset(); LibMeteor.libmeteor_loadbios(bios, (uint)bios.Length); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs index 9ae4b580ca..8a1cb5c290 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/NES/NES.cs @@ -15,8 +15,17 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES static readonly bool USE_DATABASE = true; public RomStatus RomStatus; - public NES(CoreComm comm, GameInfo game, byte[] rom, byte[] fdsbios = null, Dictionary boardProperties = null) + public NES(CoreComm comm, GameInfo game, byte[] rom, IEmuLoadHelper EmuLoadHelper, Dictionary boardProperties = null) { + byte[] fdsbios = EmuLoadHelper.GetFirmware("NES", "Bios_FDS", false); + if (fdsbios != null && fdsbios.Length == 40976) + { + EmuLoadHelper.ShowMessage("Your FDS BIOS is a bad dump. BizHawk will attempt to use it, but no guarantees! You should find a new one."); + var tmp = new byte[8192]; + Buffer.BlockCopy(fdsbios, 16 + 8192 * 3, tmp, 0, 8192); + fdsbios = tmp; + } + if (boardProperties != null) { InitialMapperRegisterValues.Set(boardProperties); diff --git a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs index c8b97c945b..5014442445 100644 --- a/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs +++ b/BizHawk.Emulation.Cores/Consoles/Nintendo/SNES/LibsnesCore.cs @@ -254,8 +254,15 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES LibsnesApi.snes_trace_t tracecb; LibsnesApi.snes_audio_sample_t soundcb; - public void Load(GameInfo game, byte[] romData, byte[] sgbRomData, bool DeterministicEmulation, byte[] xmlData) + public void Load(GameInfo game, byte[] romData, IEmuLoadHelper EmuLoadHelper, bool DeterministicEmulation, byte[] xmlData) { + byte[] sgbRomData = null; + if (game["SGB"]) + { + sgbRomData = EmuLoadHelper.GetFirmware("SNES", "Rom_SGB", true, "SGB Rom is required for SGB emulation."); + game.FirmwareHash = Util.Hash_SHA1(sgbRomData); + } + ScanlineHookManager = new MyScanlineHookManager(this); api.CMD_init(); diff --git a/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Yabause.cs b/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Yabause.cs index 6e211b73bd..fb8b1d1741 100644 --- a/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Yabause.cs +++ b/BizHawk.Emulation.Cores/Consoles/Sega/Saturn/Yabause.cs @@ -41,8 +41,9 @@ namespace BizHawk.Emulation.Cores.Sega.Saturn LibYabause.InputCallback InputCallbackH; - public Yabause(CoreComm CoreComm, DiscSystem.Disc CD, byte[] bios, bool GL = false) + public Yabause(CoreComm CoreComm, DiscSystem.Disc CD, IEmuLoadHelper EmuLoadHelper, bool GL) { + byte[] bios = EmuLoadHelper.GetFirmware("SAT", "J", true, "Saturn BIOS is required."); CoreComm.RomStatusDetails = string.Format("Disk partial hash:{0}", CD.GetHash()); this.CoreComm = CoreComm; this.CD = CD;