private void ComputeBootGod() { // inefficient, sloppy, etc etc var chrrom = _memoryDomains["CHR VROM"]; var prgrom = _memoryDomains["PRG ROM"] !; var ms = new MemoryStream(); for (int i = 0; i < prgrom.Size; i++) { ms.WriteByte(prgrom.PeekByte(i)); } if (chrrom != null) { for (int i = 0; i < chrrom.Size; i++) { ms.WriteByte(chrrom.PeekByte(i)); } } var sha1 = SHA1Checksum.ComputeDigestHex(ms.ToArray()); Console.WriteLine("Hash for BootGod: {0}", sha1); // Bail out on ROM's known to not be playable by this core if (HashBlackList.Contains(sha1)) { throw new UnsupportedGameException("Game known to not be playable in this core"); } sha1 = "sha1:" + sha1; // huh? var carts = BootGodDb.Identify(sha1); if (carts.Count > 0) { Console.WriteLine("BootGod entry found: {0}", carts[0].Name); switch (carts[0].System) { case "NES-PAL": case "NES-PAL-A": case "NES-PAL-B": case "Dendy": Console.WriteLine("Bad region {0}! Failing over...", carts[0].System); throw new UnsupportedGameException("Unsupported region!"); } BootGodStatus = RomStatus.GoodDump; BootGodName = carts[0].Name; } else { Console.WriteLine("No BootGod entry found."); BootGodStatus = null; BootGodName = null; } }
// ICreateGameDBEntries public CompactGameInfo GenerateGameDbEntry() { return(new CompactGameInfo { Name = _game.Name, System = VSystemID.Raw.A26, MetaData = "m=" + _mapper.GetType().ToString().Split('.').Last(), Hash = SHA1Checksum.ComputeDigestHex(Rom), Region = _game.Region, Status = RomStatus.Unknown }); }
// Fix some incorrect ines header entries that QuickNES uses to load games. // we need to do this from the raw file since QuickNES hasn't had time to process it yet. private byte[] FixInesHeader(byte[] file) { var sha1 = SHA1Checksum.ComputeDigestHex(file); bool didSomething = false; Console.WriteLine(sha1); if (sha1 == "93010514AA1300499ABC8F145D6ABCDBF3084090") // Ms. Pac Man (Tengen) [!] { file[6] &= 0xFE; didSomething = true; } if (didSomething) { Console.WriteLine("iNES header error detected, adjusting settings..."); Console.WriteLine(sha1); } return(file); }
public LibsnesCore(GameInfo game, byte[] romData, byte[] xmlData, string baseRomPath, CoreComm comm, LibsnesCore.SnesSettings settings, LibsnesCore.SnesSyncSettings syncSettings) { _baseRomPath = baseRomPath; var ser = new BasicServiceProvider(this); ServiceProvider = ser; const string TRACE_HEADER = "65816: PC, mnemonic, operands, registers (A, X, Y, S, D, DB, flags (NVMXDIZC), V, H)"; _tracer = new TraceBuffer(TRACE_HEADER); ser.Register <IDisassemblable>(new W65816_DisassemblerService()); _game = game; CoreComm = comm; byte[] sgbRomData = null; if (game.System == VSystemID.Raw.SGB) { if ((romData[0x143] & 0xc0) == 0xc0) { throw new CGBNotSupportedException(); } sgbRomData = CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("SNES", "Rom_SGB"), "SGB Rom is required for SGB emulation."); game.FirmwareHash = SHA1Checksum.ComputeDigestHex(sgbRomData); } _settings = (SnesSettings)settings ?? new SnesSettings(); _syncSettings = (SnesSyncSettings)syncSettings ?? new SnesSyncSettings(); _videocb = snes_video_refresh; _inputpollcb = snes_input_poll; _inputstatecb = snes_input_state; _inputnotifycb = snes_input_notify; _scanlineStartCb = snes_scanlineStart; _tracecb = snes_trace; _soundcb = snes_audio_sample; _pathrequestcb = snes_path_request; // TODO: pass profile here Api = new LibsnesApi(CoreComm.CoreFileProvider.DllPath(), CoreComm, new Delegate[] { _videocb, _inputpollcb, _inputstatecb, _inputnotifycb, _scanlineStartCb, _tracecb, _soundcb, _pathrequestcb }) { ReadHook = ReadHook, ExecHook = ExecHook, WriteHook = WriteHook, ReadHook_SMP = ReadHook_SMP, ExecHook_SMP = ExecHook_SMP, WriteHook_SMP = WriteHook_SMP, }; ScanlineHookManager = new MyScanlineHookManager(this); _controllerDeck = new LibsnesControllerDeck(_syncSettings); _controllerDeck.NativeInit(Api); Api.CMD_init(_syncSettings.RandomizedInitialState); Api.QUERY_set_path_request(_pathrequestcb); // start up audio resampler InitAudio(); ser.Register <ISoundProvider>(_resampler); // strip header if ((romData?.Length & 0x7FFF) == 512) { var newData = new byte[romData.Length - 512]; Array.Copy(romData, 512, newData, 0, newData.Length); romData = newData; } if (game.System == VSystemID.Raw.SGB) { IsSGB = true; SystemId = VSystemID.Raw.SNES; ser.Register <IBoardInfo>(new SGBBoardInfo()); _currLoadParams = new LoadParams { type = LoadParamType.SuperGameBoy, rom_xml = null, rom_data = sgbRomData, rom_size = (uint)sgbRomData.Length, dmg_data = romData, }; if (!LoadCurrent()) { throw new Exception("snes_load_cartridge_normal() failed"); } } else { // we may need to get some information out of the cart, even during the following bootup/load process if (xmlData != null) { _romxml = new XmlDocument(); _romxml.Load(new MemoryStream(xmlData)); // bsnes wont inspect the xml to load the necessary sfc file. // so, we have to do that here and pass it in as the romData :/ if (_romxml["cartridge"]?["rom"] != null) { romData = File.ReadAllBytes(PathSubfile(_romxml["cartridge"]["rom"].Attributes["name"].Value)); } else { throw new Exception("Could not find rom file specification in xml file. Please check the integrity of your xml file"); } } SystemId = VSystemID.Raw.SNES; _currLoadParams = new LoadParams { type = LoadParamType.Normal, xml_data = xmlData, rom_data = romData }; if (!LoadCurrent()) { throw new Exception("snes_load_cartridge_normal() failed"); } } if (_region == LibsnesApi.SNES_REGION.NTSC) { // similar to what aviout reports from snes9x and seems logical from bsnes first principles. bsnes uses that numerator (ntsc master clockrate) for sure. VsyncNumerator = 21477272; VsyncDenominator = 4 * 341 * 262; } else { // http://forums.nesdev.com/viewtopic.php?t=5367&start=19 VsyncNumerator = 21281370; VsyncDenominator = 4 * 341 * 312; } Api.CMD_power(); SetupMemoryDomains(romData, sgbRomData); if (CurrentProfile == "Compatibility") { ser.Register <ITraceable>(_tracer); } Api.QUERY_set_path_request(null); Api.QUERY_set_video_refresh(_videocb); Api.QUERY_set_input_poll(_inputpollcb); Api.QUERY_set_input_state(_inputstatecb); Api.QUERY_set_input_notify(_inputnotifycb); Api.QUERY_set_audio_sample(_soundcb); Api.Seal(); RefreshPalette(); }
} = new List <string>(); // TODO: Hack work around, to avoid having to refactor Assets into a object array, should be refactored! /// <exception cref="InvalidOperationException">internal error</exception> public static XmlGame Create(HawkFile f) { try { var x = new XmlDocument(); x.Load(f.GetStream()); var y = x.SelectSingleNode("./BizHawk-XMLGame"); if (y == null) { return(null); } var ret = new XmlGame { GI = { System = y.Attributes["System"].Value, Name = y.Attributes["Name"].Value, Status = RomStatus.Unknown }, Xml = x }; string fullPath = ""; var n = y.SelectSingleNode("./LoadAssets"); if (n != null) { var hashStream = new MemoryStream(); int?originalIndex = null; foreach (XmlNode a in n.ChildNodes) { string filename = a.Attributes["FileName"].Value; byte[] data; if (filename[0] == '|') { // in same archive var ai = f.FindArchiveMember(filename.Substring(1)); if (ai != null) { originalIndex ??= f.BoundIndex; f.Unbind(); f.BindArchiveMember(ai.Value); data = f.GetStream().ReadAllBytes(); } else { throw new Exception($"Couldn't load XMLGame Asset \"{filename}\""); } } else { // relative path fullPath = Path.GetDirectoryName(f.CanonicalFullPath.Split('|').First()) ?? ""; fullPath = Path.Combine(fullPath, filename.Split('|').First()); try { using var hf = new HawkFile(fullPath); if (hf.IsArchive) { var archiveItem = hf.ArchiveItems.First(ai => ai.Name == filename.Split('|').Skip(1).First()); hf.Unbind(); hf.BindArchiveMember(archiveItem); data = hf.GetStream().ReadAllBytes(); filename = filename.Split('|').Skip(1).First(); } else { data = File.ReadAllBytes(fullPath.Split('|').First()); } } catch { throw new Exception($"Couldn't load XMLGame LoadAsset \"{filename}\""); } } ret.Assets.Add(new KeyValuePair <string, byte[]>(filename, data)); ret.AssetFullPaths.Add(fullPath); var sha1 = SHA1Checksum.Compute(data); hashStream.Write(sha1, 0, sha1.Length); } ret.GI.Hash = SHA1Checksum.ComputeDigestHex(hashStream.GetBufferAsSpan()); hashStream.Close(); if (originalIndex != null) { f.Unbind(); f.BindArchiveMember((int)originalIndex); } } else { ret.GI.Hash = SHA1Checksum.Zero; } return(ret); } catch (Exception ex) { throw new InvalidOperationException(ex.ToString()); } }
public BsnesCore(CoreLoadParameters <SnesSettings, SnesSyncSettings> loadParameters) { var ser = new BasicServiceProvider(this); ServiceProvider = ser; this._romPath = Path.Combine(loadParameters.Roms[0].RomDirectory, loadParameters.Game.Name); CoreComm = loadParameters.Comm; _settings = loadParameters.Settings ?? new SnesSettings(); _syncSettings = loadParameters.SyncSettings ?? new SnesSyncSettings(); IsSGB = loadParameters.Game.System == VSystemID.Raw.SGB; byte[] sgbRomData = null; if (IsSGB) { if ((loadParameters.Roms[0].RomData[0x143] & 0xc0) == 0xc0) { throw new CGBNotSupportedException(); } sgbRomData = _syncSettings.UseSGB2 ? CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("SNES", "Rom_SGB2"), "SGB2 Rom is required for SGB2 emulation.") : CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("SNES", "Rom_SGB"), "SGB1 Rom is required for SGB1 emulation."); loadParameters.Game.FirmwareHash = SHA1Checksum.ComputeDigestHex(sgbRomData); } BsnesApi.SnesCallbacks callbacks = new() { inputPollCb = snes_input_poll, noLagCb = snes_no_lag, controllerLatchCb = snes_controller_latch, videoFrameCb = snes_video_refresh, audioSampleCb = snes_audio_sample, pathRequestCb = snes_path_request, traceCb = snes_trace, readHookCb = ReadHook, writeHookCb = WriteHook, execHookCb = ExecHook, msuOpenCb = msu_open, msuSeekCb = msu_seek, msuReadCb = msu_read, msuEndCb = msu_end }; Api = new BsnesApi(CoreComm.CoreFileProvider.DllPath(), CoreComm, callbacks.AllDelegatesInMemoryOrder()); _controllers = new BsnesControllers(_syncSettings); generate_palette(); BsnesApi.SnesInitData snesInitData = new() { entropy = _syncSettings.Entropy, left_port = _syncSettings.LeftPort, right_port = _syncSettings.RightPort, hotfixes = _syncSettings.Hotfixes, fast_ppu = _syncSettings.FastPPU, fast_dsp = _syncSettings.FastDSP, fast_coprocessors = _syncSettings.FastCoprocessors, region_override = _syncSettings.RegionOverride, }; Api.core.snes_init(ref snesInitData); Api.SetCallbacks(callbacks); // start up audio resampler InitAudio(); ser.Register <ISoundProvider>(_resampler); if (IsSGB) { ser.Register <IBoardInfo>(new SGBBoardInfo()); Api.core.snes_load_cartridge_super_gameboy(sgbRomData, loadParameters.Roms[0].RomData, sgbRomData !.Length, loadParameters.Roms[0].RomData.Length); } else { Api.core.snes_load_cartridge_normal(loadParameters.Roms[0].RomData, loadParameters.Roms[0].RomData.Length); } _region = Api.core.snes_get_region(); if (_region == BsnesApi.SNES_REGION.NTSC) { // taken from bsnes source VsyncNumerator = 21477272; VsyncDenominator = 357366; } else { // http://forums.nesdev.com/viewtopic.php?t=5367&start=19 VsyncNumerator = 21281370; VsyncDenominator = 4 * 341 * 312; } SetMemoryDomains(); const string TRACE_HEADER = "65816: PC, mnemonic, operands, registers (A, X, Y, S, D, B, flags (NVMXDIZC), V, H)"; _tracer = new TraceBuffer(TRACE_HEADER); ser.Register <IDisassemblable>(new W65816_DisassemblerService()); ser.Register(_tracer); Api.Seal(); }
public PCEngine(CoreLoadParameters <PCESettings, PCESyncSettings> lp) { if (lp.Discs.Count == 1 && lp.Roms.Count == 0) { SystemId = VSystemID.Raw.PCECD; Type = NecSystemType.TurboCD; this.disc = lp.Discs[0].DiscData; Settings = (PCESettings)lp.Settings ?? new PCESettings(); _syncSettings = (PCESyncSettings)lp.SyncSettings ?? new PCESyncSettings(); var(rom, biosInfo) = lp.Comm.CoreFileProvider.GetFirmwareWithGameInfoOrThrow( new("PCECD", "Bios"), "PCE-CD System Card not found. Please check the BIOS settings in Config->Firmwares."); if (biosInfo.Status == RomStatus.BadDump) { lp.Comm.ShowMessage( "The PCE-CD System Card you have selected is known to be a bad dump. This may cause problems playing PCE-CD games.\n\n" + "It is recommended that you find a good dump of the system card. Sorry to be the bearer of bad news!"); } else if (biosInfo.NotInDatabase) { lp.Comm.ShowMessage( "The PCE-CD System Card you have selected is not recognized in our database. That might mean it's a bad dump, or isn't the correct rom."); } else if (biosInfo["BIOS"] == false) { // zeromus says: someone please write a note about how this could possibly happen. // it seems like this is a relic of using gameDB for storing whether something is a bios? firmwareDB should be handling it now. lp.Comm.ShowMessage( "The PCE-CD System Card you have selected is not a BIOS image. You may have selected the wrong rom. FYI-Please report this to developers, I don't think this error message should happen."); } if (biosInfo["SuperSysCard"]) { lp.Game.AddOption("SuperSysCard", ""); } if (lp.Game["NeedSuperSysCard"] && lp.Game["SuperSysCard"] == false) { lp.Comm.ShowMessage( "This game requires a version 3.0 System card and won't run with the system card you've selected. Try selecting a 3.0 System Card in the firmware configuration."); throw new Exception(); } lp.Game.FirmwareHash = SHA1Checksum.ComputeDigestHex(rom); Init(lp.Game, rom); // the default RomStatusDetails don't do anything with Disc RomDetails = $"{lp.Game.Name}\r\nDisk partial hash:{new DiscHasher(disc).OldHash()}"; _controllerDeck = new PceControllerDeck( _syncSettings.Port1, _syncSettings.Port2, _syncSettings.Port3, _syncSettings.Port4, _syncSettings.Port5); } else if (lp.Discs.Count == 0 && lp.Roms.Count == 1) { switch (SystemId = lp.Game.System) { default: case VSystemID.Raw.PCE: Type = NecSystemType.TurboGrafx; break; case VSystemID.Raw.SGX: Type = NecSystemType.SuperGrafx; break; } Settings = (PCESettings)lp.Settings ?? new PCESettings(); _syncSettings = (PCESyncSettings)lp.SyncSettings ?? new PCESyncSettings(); Init(lp.Game, lp.Roms[0].RomData); _controllerDeck = new PceControllerDeck( _syncSettings.Port1, _syncSettings.Port2, _syncSettings.Port3, _syncSettings.Port4, _syncSettings.Port5); } else { throw new InvalidOperationException("PCEHawk can only load exactly one CD or exactly one ROM"); } }
public BsnesCore(GameInfo game, byte[] romData, byte[] xmlData, string baseRomPath, CoreComm comm, SnesSettings settings, SnesSyncSettings syncSettings) { _baseRomPath = baseRomPath; var ser = new BasicServiceProvider(this); ServiceProvider = ser; CoreComm = comm; byte[] sgbRomData = null; _settings = settings ?? new SnesSettings(); _syncSettings = syncSettings ?? new SnesSyncSettings(); if (game.System == VSystemID.Raw.SGB) { if ((romData[0x143] & 0xc0) == 0xc0) { throw new CGBNotSupportedException(); } sgbRomData = _syncSettings.UseSGB2 ? CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("SNES", "Rom_SGB2"), "SGB2 Rom is required for SGB2 emulation.") : CoreComm.CoreFileProvider.GetFirmwareOrThrow(new("SNES", "Rom_SGB"), "SGB1 Rom is required for SGB1 emulation."); game.FirmwareHash = SHA1Checksum.ComputeDigestHex(sgbRomData); } BsnesApi.SnesCallbacks callbacks = new() { inputPollCb = snes_input_poll, noLagCb = snes_no_lag, controllerLatchCb = snes_controller_latch, videoFrameCb = snes_video_refresh, audioSampleCb = snes_audio_sample, pathRequestCb = snes_path_request, traceCb = snes_trace, readHookCb = ReadHook, writeHookCb = WriteHook, execHookCb = ExecHook }; Api = new BsnesApi(CoreComm.CoreFileProvider.DllPath(), CoreComm, callbacks.AllDelegatesInMemoryOrder()); _controllers = new BsnesControllers(_syncSettings); generate_palette(); // TODO: massive random hack till waterboxhost gets fixed to support 5+ args ushort mergedBools = (ushort)((_syncSettings.Hotfixes ? 1 << 8 : 0) | (_syncSettings.FastPPU ? 1 : 0)); Api.core.snes_init(_syncSettings.Entropy, _syncSettings.LeftPort, _syncSettings.RightPort, mergedBools); Api.SetCallbacks(callbacks); // start up audio resampler InitAudio(); ser.Register <ISoundProvider>(_resampler); if (game.System == VSystemID.Raw.SGB) { IsSGB = true; SystemId = VSystemID.Raw.SNES; ser.Register <IBoardInfo>(new SGBBoardInfo()); _currLoadParams = new LoadParams { type = LoadParamType.SuperGameBoy, baseRomPath = baseRomPath, romData = sgbRomData, sgbRomData = romData }; } else { // we may need to get some information out of the cart, even during the following bootup/load process if (xmlData != null) { _romxml = new XmlDocument(); _romxml.Load(new MemoryStream(xmlData)); // bsnes wont inspect the xml to load the necessary sfc file. // so, we have to do that here and pass it in as the romData :/ // TODO: uhh i have no idea what the xml is or whether this below code is needed if (_romxml["cartridge"]?["rom"] != null) { romData = File.ReadAllBytes(PathSubfile(_romxml["cartridge"]["rom"].Attributes["name"].Value)); } else { throw new Exception("Could not find rom file specification in xml file. Please check the integrity of your xml file"); } } SystemId = VSystemID.Raw.SNES; _currLoadParams = new LoadParams { type = LoadParamType.Normal, baseRomPath = baseRomPath, romData = romData }; } LoadCurrent(); if (_region == BsnesApi.SNES_REGION.NTSC) { // taken from bsnes source VsyncNumerator = 21477272; VsyncDenominator = 357366; } else { // http://forums.nesdev.com/viewtopic.php?t=5367&start=19 VsyncNumerator = 21281370; VsyncDenominator = 4 * 341 * 312; } SetMemoryDomains(); const string TRACE_HEADER = "65816: PC, mnemonic, operands, registers (A, X, Y, S, D, B, flags (NVMXDIZC), V, H)"; _tracer = new TraceBuffer(TRACE_HEADER); ser.Register <IDisassemblable>(new W65816_DisassemblerService()); ser.Register(_tracer); Api.Seal(); }