diff --git a/BizHawk.Emulation/BizHawk.Emulation.csproj b/BizHawk.Emulation/BizHawk.Emulation.csproj index f4b8b3c87d..99080284cc 100644 --- a/BizHawk.Emulation/BizHawk.Emulation.csproj +++ b/BizHawk.Emulation/BizHawk.Emulation.csproj @@ -181,6 +181,7 @@ + @@ -205,7 +206,6 @@ - diff --git a/BizHawk.Emulation/Consoles/Calculator/TI83.cs b/BizHawk.Emulation/Consoles/Calculator/TI83.cs index 15a661cc59..07c3bfa903 100644 --- a/BizHawk.Emulation/Consoles/Calculator/TI83.cs +++ b/BizHawk.Emulation/Consoles/Calculator/TI83.cs @@ -315,7 +315,7 @@ namespace BizHawk.Emulation.Consoles.Calculator } } - public TI83() + public TI83(GameInfo game, byte[] rom) { CoreOutputComm = new CoreOutputComm(); cpu.ReadMemory = ReadMemory; @@ -324,6 +324,18 @@ namespace BizHawk.Emulation.Consoles.Calculator cpu.WriteHardware = WriteHardware; cpu.IRQCallback = IRQCallback; cpu.NMICallback = NMICallback; + + this.rom = rom; + + //different calculators (different revisions?) have different initPC. we track this in the game database by rom hash + //if( *(unsigned long *)(m_pRom + 0x6ce) == 0x04D3163E ) m_Regs.PC.W = 0x6ce; //KNOWN + //else if( *(unsigned long *)(m_pRom + 0x6f6) == 0x04D3163E ) m_Regs.PC.W = 0x6f6; //UNKNOWN + + if (game["initPC"]) + startPC = ushort.Parse(game.OptionValue("initPC"), NumberStyles.HexNumber); + + HardReset(); + SetupMemoryDomains(); } void IRQCallback() @@ -406,23 +418,6 @@ namespace BizHawk.Emulation.Consoles.Calculator //configuration ushort startPC; - public void LoadGame(IGame game) - { - rom = game.GetRomData(); - foreach (string opt in game.GetOptions()) - { - //different calculators (different revisions?) have different initPC. we track this in the game database by rom hash - //if( *(unsigned long *)(m_pRom + 0x6ce) == 0x04D3163E ) m_Regs.PC.W = 0x6ce; //KNOWN - //else if( *(unsigned long *)(m_pRom + 0x6f6) == 0x04D3163E ) m_Regs.PC.W = 0x6f6; //UNKNOWN - - if (opt.StartsWith("initPC")) - startPC = ushort.Parse(opt.Split('=')[1], NumberStyles.HexNumber); - } - - HardReset(); - SetupMemoryDomains(); - } - public void FrameAdvance(bool render) { lagged = true; diff --git a/BizHawk.Emulation/Consoles/Gameboy/Gameboy.cs b/BizHawk.Emulation/Consoles/Gameboy/Gameboy.cs index 047708992e..dc5c994874 100644 --- a/BizHawk.Emulation/Consoles/Gameboy/Gameboy.cs +++ b/BizHawk.Emulation/Consoles/Gameboy/Gameboy.cs @@ -269,7 +269,7 @@ namespace BizHawk.Emulation.Consoles.Gameboy { CoreOutputComm = new CoreOutputComm(); } - + /* TOO BAD gameboy is broken until someone cares about it public void LoadGame(IGame game) { Rom = game.GetRomData(); @@ -281,7 +281,7 @@ namespace BizHawk.Emulation.Consoles.Gameboy CartFlags.SGB = Rom[0x0146] == 0x03; HardReset(); - } + } */ public bool BootFromBios = true; diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs index 7846d0f19c..d1dfa5531a 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/BoardSystem.cs @@ -215,7 +215,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo /// public class CartInfo { - public GameInfo game; + public NESGameInfo game; public BizHawk.GameInfo DB_GameInfo; public short chr_size; @@ -241,7 +241,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo /// /// Logical game information. May exist in form of several carts (different revisions) /// - public class GameInfo + public class NESGameInfo { public string name; public List carts = new List(); @@ -285,12 +285,12 @@ namespace BizHawk.Emulation.Consoles.Nintendo var gi = Database.CheckDatabase(hash); if (gi == null) return null; - GameInfo game = new GameInfo(); + NESGameInfo game = new NESGameInfo(); CartInfo cart = new CartInfo(); game.carts.Add(cart); //try generating a bootgod cart descriptor from the game database - var dict = gi.ParseOptionsDictionary(); + var dict = gi.GetOptionsDict(); game.name = gi.Name; cart.DB_GameInfo = gi; cart.game = game; @@ -344,7 +344,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo //in anticipation of any slowness annoying people, and just for shits and giggles, i made a super fast parser int state=0; var xmlreader = XmlReader.Create(new MemoryStream(GetDatabaseBytes())); - GameInfo currGame = null; + NESGameInfo currGame = null; CartInfo currCart = null; while (xmlreader.Read()) { @@ -353,7 +353,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo case 0: if (xmlreader.NodeType == XmlNodeType.Element && xmlreader.Name == "game") { - currGame = new GameInfo(); + currGame = new NESGameInfo(); currGame.name = xmlreader.GetAttribute("name"); state = 1; } @@ -432,7 +432,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo } //end xmlreader loop //analyze - foreach (GameInfo game in games) + foreach (NESGameInfo game in games) { foreach (CartInfo cart in game.carts) { @@ -442,7 +442,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo } - List games = new List(); //maybe we dont need to track this + List games = new List(); //maybe we dont need to track this Bag sha1_table = new Bag(); public List Identify(string sha1) diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs index d076284af3..639fbd43c6 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/NES.cs @@ -14,7 +14,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo public partial class NES : IEmulator { static readonly bool USE_DATABASE = true; - + public RomStatus RomStatus; //Game issues: //Tecmo superbowl - wobbly "NFL" logo at the end of a game (even skipped game) [zeromus cant test this; how do you skip game?] //Bigfoot (U) seems not to work @@ -37,14 +37,20 @@ namespace BizHawk.Emulation.Consoles.Nintendo //AD&D Hillsfar (U).nes black screen //Air Wolf - big graphical glitch. seems to be a real bug, but it should never have been released with this. need to verify for sure that it is a real bug? - public NES() + public NES(GameInfo game, byte[] rom) { CoreOutputComm = new CoreOutputComm(); BootGodDB.Initialize(); SetPalette(Palettes.FCEUX_Standard); videoProvider = new MyVideoProvider(this); + Init(game, rom); } + private NES() + { + BootGodDB.Initialize(); + } + public void WriteLogTimestamp() { if (ppu != null) @@ -353,13 +359,13 @@ namespace BizHawk.Emulation.Consoles.Nintendo LoadReport.WriteLine(format, arg); } void LoadWriteLine(object arg) { LoadWriteLine("{0}", arg); } - - public unsafe void LoadGame(IGame game) + + public unsafe void Init(GameInfo gameInfo, byte[] rom) { LoadReport = new StringWriter(); LoadWriteLine("------"); LoadWriteLine("BEGIN NES rom analysis:"); - byte[] file = game.GetFileData(); + byte[] file = rom; if (file.Length < 16) throw new Exception("Alleged NES rom too small to be anything useful"); if (file.Take(4).SequenceEqual(System.Text.Encoding.ASCII.GetBytes("UNIF"))) throw new Exception("You've tried to open a UNIF rom. We don't have any UNIF roms to test with. Please consult the developers."); @@ -437,7 +443,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo } LoadWriteLine("Chose board from iNES heuristics: " + iNES_board); - choice.game.name = game.Name; + choice.game.name = gameInfo.Name; origin = EDetectionOrigin.INES; } else @@ -486,23 +492,23 @@ namespace BizHawk.Emulation.Consoles.Nintendo if (origin == EDetectionOrigin.BootGodDB) { - CoreOutputComm.RomStatus = RomStatus.GoodDump; + RomStatus = RomStatus.GoodDump; CoreOutputComm.RomStatusAnnotation = "Identified from BootGod's database"; } if (origin == EDetectionOrigin.INES) { - CoreOutputComm.RomStatus = RomStatus.NotInDatabase; + RomStatus = RomStatus.NotInDatabase; CoreOutputComm.RomStatusAnnotation = "Inferred from iNES header; potentially wrong"; } if (origin == EDetectionOrigin.GameDB) { if (choice.bad) { - CoreOutputComm.RomStatus = RomStatus.BadDump; + RomStatus = RomStatus.BadDump; } else { - CoreOutputComm.RomStatus = choice.DB_GameInfo.Status; + RomStatus = choice.DB_GameInfo.Status; } } @@ -525,10 +531,10 @@ namespace BizHawk.Emulation.Consoles.Nintendo if (cart.vram_size != 0) board.VRAM = new byte[cart.vram_size * 1024]; + HardReset(); SetupMemoryDomains(); } - } void SyncState(Serializer ser) diff --git a/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs b/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs index 6f06ec9a72..b966856120 100644 --- a/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs +++ b/BizHawk.Emulation/Consoles/Nintendo/NES/iNES.cs @@ -152,7 +152,7 @@ static string ClassifyTable = @" public CartInfo Analyze() { var ret = new CartInfo(); - ret.game = new GameInfo(); + ret.game = new NESGameInfo(); int mapper = (ROM_type >> 4); mapper |= (ROM_type2 & 0xF0); ret.mapper = (byte)mapper; diff --git a/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs b/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs index 1a9fcfc13f..0f5c5a2070 100644 --- a/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs +++ b/BizHawk.Emulation/Consoles/PC Engine/PCEngine.cs @@ -20,6 +20,7 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx // ROM public byte[] RomData; public int RomLength; + private Disc disc; // Machine public NecSystemType Type; @@ -41,19 +42,31 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx // Memory system public byte[] Ram; - // Disc - //private Disc disc = Disc.FromCuePath("D:/lib/roms/Turbo CD/Terra Forming/Syd Mead's Terra Forming [U][CD.SCD][TGXCD1040][Syd Mead][1993][PCE][rigg].cue"); - // PC Engine timings: // 21,477,270 Machine clocks / sec // 7,159,090 Cpu cycles / sec - public PCEngine(NecSystemType type) + public PCEngine(GameInfo game, byte[] rom) { - //scsi.disc = disc; - //Console.WriteLine(disc.GetHash()); CoreOutputComm = new CoreOutputComm(); - Type = type; + switch (game.System) + { + case "PCE": Type = NecSystemType.TurboGrafx; break; + case "SGX": Type = NecSystemType.SuperGrafx; break; + } + Init(game, rom); + } + + public PCEngine(GameInfo game, Disc disc, byte[] rom) + { + CoreOutputComm = new CoreOutputComm(); + Type = NecSystemType.TurboCD; + this.disc = disc; + Init(game, rom); + } + + private void Init(GameInfo game, byte[] rom) + { Controller = NullController.GetNullController(); Cpu = new HuC6280(); VCE = new VCE(); @@ -77,34 +90,31 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx Cpu.WriteMemory21 = WriteMemorySGX; Cpu.WriteVDC = VDC1.WriteVDC; } - } - public void LoadGame(IGame game) - { - if (game.GetRomData().Length == 0x60000) + if (rom.Length == 0x60000) { // 384k roms require special loading code. Why ;_; // In memory, 384k roms look like [1st 256k][Then full 384k] RomData = new byte[0xA0000]; - var origRom = game.GetRomData(); + var origRom = rom; for (int i=0; i<0x40000; i++) RomData[i] = origRom[i]; for (int i = 0; i < 0x60000; i++) RomData[i+0x40000] = origRom[i]; RomLength = RomData.Length; - } else if (game.GetRomData().Length > 1024 * 1024) { + } else if (rom.Length > 1024 * 1024) { // If the rom is bigger than 1 megabyte, switch to Street Fighter 2 mapper Cpu.ReadMemory21 = ReadMemorySF2; Cpu.WriteMemory21 = WriteMemorySF2; - RomData = game.GetRomData(); + RomData = rom; RomLength = RomData.Length; } else { // normal rom. - RomData = game.GetRomData(); + RomData = rom; RomLength = RomData.Length; } - if (game.GetOptions().Contains("BRAM")) + if (game["BRAM"]) { BramEnabled = true; BRAM = new byte[2048]; @@ -115,14 +125,14 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx BRAM[4] = 0x00; BRAM[5] = 0x88; BRAM[6] = 0x10; BRAM[7] = 0x80; } - if (game.GetOptions().Contains("PopulousSRAM")) + if (game["PopulousSRAM"]) { PopulousRAM = new byte[0x8000]; Cpu.ReadMemory21 = ReadMemoryPopulous; Cpu.WriteMemory21 = WriteMemoryPopulous; } - if (game.GetOptions().Contains("ForceSpriteLimit") || game.GetOptions().Contains("NotInDatabase")) + if (game["ForceSpriteLimit"] || game.NotInDatabase) { VDC1.PerformSpriteLimit = true; if (VDC2 != null) @@ -138,14 +148,14 @@ namespace BizHawk.Emulation.Consoles.TurboGrafx // version of this core. Let's just acknolwedge that the timing is imperfect and fix // it in the least intrusive and most honest way we can. - if (game.GetOptions().ContainsStartsWith("HBlankPeriod")) - VDC1.HBlankCycles = int.Parse(game.GetOptions().GetOptionValue("HBlankPeriod")); + if (game["HBlankPeriod"]) + VDC1.HBlankCycles = int.Parse(game.OptionValue("HBlankPeriod")); // This is also a hack. Proper multi-res/TV emulation will be a native-code core feature. - if (game.GetOptions().ContainsStartsWith("MultiResHack")) + if (game["MultiResHack"]) { - VDC1.MultiResHack = int.Parse(game.GetOptions().GetOptionValue("MultiResHack")); + VDC1.MultiResHack = int.Parse(game.OptionValue("MultiResHack")); } Cpu.ResetPC(); diff --git a/BizHawk.Emulation/Consoles/Sega/Genesis/Genesis.cs b/BizHawk.Emulation/Consoles/Sega/Genesis/Genesis.cs index 32bbf8a73d..0566a44d88 100644 --- a/BizHawk.Emulation/Consoles/Sega/Genesis/Genesis.cs +++ b/BizHawk.Emulation/Consoles/Sega/Genesis/Genesis.cs @@ -83,6 +83,7 @@ namespace BizHawk.Emulation.Consoles.Sega Z80Reset = true; } + /* TOO BAD genesis is broken until I finish turbocd public void LoadGame(IGame game) { RomData = new byte[0x400000]; @@ -92,7 +93,7 @@ namespace BizHawk.Emulation.Consoles.Sega if (MainCPU != null) MainCPU.Reset(); _MainCPU.Reset(); - } + }*/ public void StepMine() { diff --git a/BizHawk.Emulation/Consoles/Sega/SMS/SMS.cs b/BizHawk.Emulation/Consoles/Sega/SMS/SMS.cs index 3db7e793a7..25f1b06e0f 100644 --- a/BizHawk.Emulation/Consoles/Sega/SMS/SMS.cs +++ b/BizHawk.Emulation/Consoles/Sega/SMS/SMS.cs @@ -25,7 +25,6 @@ namespace BizHawk.Emulation.Consoles.Sega public byte[] RomData; public byte RomBank0, RomBank1, RomBank2; public byte RomBanks; - public IList Options; // SaveRAM public byte[] SaveRAM = new byte[BankSize * 2]; @@ -64,76 +63,63 @@ namespace BizHawk.Emulation.Consoles.Sega public DisplayType DisplayType { get; set; } public bool DeterministicEmulation { get; set; } - public SMS() + public SMS(GameInfo game, byte[] rom) { + IsGameGear = game.System == "GG"; + RomData = rom; CoreOutputComm = new CoreOutputComm(); - } - public void Init() - { - if (Controller == null) - Controller = NullController.GetNullController(); + if (RomData.Length % BankSize != 0) + Array.Resize(ref RomData, ((RomData.Length / BankSize) + 1) * BankSize); + RomBanks = (byte)(RomData.Length / BankSize); + DisplayType = DisplayType.NTSC; + CoreOutputComm.VsyncRate = DisplayType == DisplayType.NTSC ? 60d : 50d; + if (game["PAL"]) DisplayType = DisplayType.PAL; + if (game["Japan"]) Region = "Japan"; + if (game.NotInDatabase || game["FM"] && game["UseFM"]) + HasYM2413 = true; - Cpu = new Z80A(); - Cpu.RegisterSP = 0xDFF0; - Cpu.ReadHardware = ReadPort; - Cpu.WriteHardware = WritePort; + if (Controller == null) + Controller = NullController.GetNullController(); - Vdp = new VDP(Cpu, IsGameGear ? VdpMode.GameGear : VdpMode.SMS, DisplayType); - PSG = new SN76489(); - YM2413 = new YM2413(); - SoundMixer = new SoundMixer(YM2413, PSG); - if (HasYM2413 && Options.Contains("WhenFMDisablePSG")) - SoundMixer.DisableSource(PSG); - ActiveSoundProvider = HasYM2413 ? (ISoundProvider)SoundMixer : PSG; + Cpu = new Z80A(); + Cpu.RegisterSP = 0xDFF0; + Cpu.ReadHardware = ReadPort; + Cpu.WriteHardware = WritePort; - SystemRam = new byte[0x2000]; - if (Options.Contains("CMMapper") == false) - InitSegaMapper(); - else - InitCodeMastersMapper(); + Vdp = new VDP(Cpu, IsGameGear ? VdpMode.GameGear : VdpMode.SMS, DisplayType); + PSG = new SN76489(); + YM2413 = new YM2413(); + SoundMixer = new SoundMixer(YM2413, PSG); + if (HasYM2413 && game["WhenFMDisablePSG"]) + SoundMixer.DisableSource(PSG); + ActiveSoundProvider = HasYM2413 ? (ISoundProvider)SoundMixer : PSG; - if (Options.Contains("ForceStereo")) - { - byte stereoByte = 0xAD; - if (Options.ContainsStartsWith("StereoByte")) - { - stereoByte = byte.Parse(Options.GetOptionValue("StereoByte")); - } - PSG.StereoPanning = stereoByte; - } + SystemRam = new byte[0x2000]; + if (game["CMMapper"] == false) + InitSegaMapper(); + else + InitCodeMastersMapper(); - if (Options.Contains("AllowOverclock") && Options.Contains("OverclockSafe")) - Vdp.IPeriod = 512; + if (game["ForceStereo"]) + { + byte stereoByte = 0xAD; + if (game["StereoByte"]) + { + stereoByte = byte.Parse(game.OptionValue("StereoByte")); + } + PSG.StereoPanning = stereoByte; + } - if (Options.Contains("BIOS")) - { - Port3E = 0xF7; // Disable cartridge, enable BIOS rom - InitBiosMapper(); - } - SetupMemoryDomains(); - } + if (game["AllowOverclock"] && game["OverclockSafe"]) + Vdp.IPeriod = 512; - public void LoadGame(IGame game) - { - RomData = game.GetRomData(); - if (RomData.Length % BankSize != 0) - Array.Resize(ref RomData, ((RomData.Length / BankSize) + 1) * BankSize); - RomBanks = (byte)(RomData.Length / BankSize); - Options = game.GetOptions(); - DisplayType = DisplayType.NTSC; - CoreOutputComm.VsyncRate = DisplayType == DisplayType.NTSC ? 60d : 50d; - foreach (string option in Options) - { - var args = option.Split('='); - if (args[0] == "Japan") Region = "Japan"; - else if (args[0] == "PAL") DisplayType = DisplayType.PAL; - } - - if (Options.Contains("NotInDatabase") || (Options.Contains("FM") && Options.Contains("UseFM"))) - HasYM2413 = true; - - Init(); + if (game["BIOS"]) + { + Port3E = 0xF7; // Disable cartridge, enable BIOS rom + InitBiosMapper(); + } + SetupMemoryDomains(); } public byte ReadPort(ushort port) diff --git a/BizHawk.Emulation/Database/Database.cs b/BizHawk.Emulation/Database/Database.cs index 22f87122dd..88584c7d4e 100644 --- a/BizHawk.Emulation/Database/Database.cs +++ b/BizHawk.Emulation/Database/Database.cs @@ -1,60 +1,22 @@ using System; using System.Collections.Generic; using System.IO; -using System.Linq; using System.Threading; namespace BizHawk { - public enum RomStatus - { - GoodDump, - BadDump, - Homebrew, - TranslatedRom, - Hack, - BIOS, - Overdump, - NotInDatabase - } - - public enum HashType - { - CRC32, MD5 - } - - public class GameInfo + internal class CompactGameInfo { public string Name; public string System; public string MetaData; - public string hash; + public string Hash; public RomStatus Status; - - public string[] GetOptions() - { - if (string.IsNullOrEmpty(MetaData)) - return new string[0]; - return MetaData.Split(';').Where(opt => string.IsNullOrEmpty(opt) == false).ToArray(); - } - - public Dictionary ParseOptionsDictionary() - { - var ret = new Dictionary(); - foreach (var opt in GetOptions()) - { - var parts = opt.Split('='); - var key = parts[0]; - var value = parts.Length > 1 ? parts[1] : ""; - ret[key] = value; - } - return ret; - } } public static class Database { - private static Dictionary db = new Dictionary(); + private static Dictionary db = new Dictionary(); static string RemoveHashType(string hash) { @@ -66,10 +28,12 @@ namespace BizHawk public static GameInfo CheckDatabase(string hash) { - GameInfo ret = null; + CompactGameInfo cgi; hash = RemoveHashType(hash); - db.TryGetValue(hash, out ret); - return ret; + db.TryGetValue(hash, out cgi); + if (cgi == null) + return null; + return new GameInfo(cgi); } static void LoadDatabase_Escape(string line) @@ -103,9 +67,9 @@ namespace BizHawk if (line.Trim().Length == 0) continue; string[] items = line.Split('\t'); - var Game = new GameInfo(); + var Game = new CompactGameInfo(); //remove a hash type identifier. well don't really need them for indexing (theyre just there for human purposes) - Game.hash = RemoveHashType(items[0].ToUpper()); + Game.Hash = RemoveHashType(items[0].ToUpper()); switch (items[1].Trim()) { case "B": Game.Status = RomStatus.BadDump; break; @@ -121,10 +85,10 @@ namespace BizHawk Game.System = items[3]; Game.MetaData = items.Length >= 6 ? items[5] : null; - if (db.ContainsKey(Game.hash)) - Console.WriteLine("gamedb: Multiple hash entries {0}, duplicate detected on {1}",Game.hash, Game.Name); + if (db.ContainsKey(Game.Hash)) + Console.WriteLine("gamedb: Multiple hash entries {0}, duplicate detected on {1}",Game.Hash, Game.Name); - db[Game.hash] = Game; + db[Game.Hash] = Game; } catch { Console.WriteLine("Error parsing database entry: "+line); @@ -135,24 +99,21 @@ namespace BizHawk public static GameInfo GetGameInfo(byte[] RomData, string fileName) { - GameInfo ret; + CompactGameInfo cgi; string hash = string.Format("{0:X8}", CRC32.Calculate(RomData)); - if (db.TryGetValue(hash, out ret)) - return ret; + if (db.TryGetValue(hash, out cgi)) + return new GameInfo(cgi); hash = Util.BytesToHexString(System.Security.Cryptography.MD5.Create().ComputeHash(RomData)); - if (db.TryGetValue(hash, out ret)) - return ret; + if (db.TryGetValue(hash, out cgi)) + return new GameInfo(cgi); hash = Util.BytesToHexString(System.Security.Cryptography.SHA1.Create().ComputeHash(RomData)); - if (db.TryGetValue(hash, out ret)) - return ret; + if (db.TryGetValue(hash, out cgi)) + return new GameInfo(cgi); // rom is not in database. make some best-guesses - var Game = new GameInfo(); - Game.hash = hash; - Game.MetaData = "NotInDatabase"; - Game.Status = RomStatus.NotInDatabase; + var Game = new GameInfo { Hash = hash, Status = RomStatus.NotInDatabase }; Console.WriteLine("Game was not in DB. CRC: {0:X8} MD5: {1}", CRC32.Calculate(RomData), Util.BytesToHexString(System.Security.Cryptography.MD5.Create().ComputeHash(RomData))); diff --git a/BizHawk.Emulation/ExternalCores/PsxCore.cs b/BizHawk.Emulation/ExternalCores/PsxCore.cs index b13555d828..2e7297de7b 100644 --- a/BizHawk.Emulation/ExternalCores/PsxCore.cs +++ b/BizHawk.Emulation/ExternalCores/PsxCore.cs @@ -68,7 +68,6 @@ namespace BizHawk public CoreOutputComm CoreOutputComm { get; private set; } public IVideoProvider VideoProvider { get { return this; } } public ISoundProvider SoundProvider { get { return this; } } - public void LoadGame(IGame game) { } public unsafe void FrameAdvance(bool render) { //if (render == false) return; diff --git a/BizHawk.Emulation/Interfaces/Base Implementations/NullEmulator.cs b/BizHawk.Emulation/Interfaces/Base Implementations/NullEmulator.cs index a850c5c0dc..50c7967164 100644 --- a/BizHawk.Emulation/Interfaces/Base Implementations/NullEmulator.cs +++ b/BizHawk.Emulation/Interfaces/Base Implementations/NullEmulator.cs @@ -28,7 +28,6 @@ namespace BizHawk Frame = 0; } - public void LoadGame(IGame game) { } public void FrameAdvance(bool render) { if (render == false) return; diff --git a/BizHawk.Emulation/Interfaces/CoreComms.cs b/BizHawk.Emulation/Interfaces/CoreComms.cs index 535db1ee05..740f61fe14 100644 --- a/BizHawk.Emulation/Interfaces/CoreComms.cs +++ b/BizHawk.Emulation/Interfaces/CoreComms.cs @@ -1,6 +1,4 @@ -using System.Collections.Generic; - -namespace BizHawk +namespace BizHawk { public class CoreInputComm { @@ -12,9 +10,7 @@ namespace BizHawk public class CoreOutputComm { public double VsyncRate = 60; - public RomStatus RomStatus; public string RomStatusAnnotation; public string RomStatusDetails; } - } \ No newline at end of file diff --git a/BizHawk.Emulation/Interfaces/IEmulator.cs b/BizHawk.Emulation/Interfaces/IEmulator.cs index df401d493d..80636139c7 100644 --- a/BizHawk.Emulation/Interfaces/IEmulator.cs +++ b/BizHawk.Emulation/Interfaces/IEmulator.cs @@ -12,7 +12,6 @@ namespace BizHawk ControllerDefinition ControllerDefinition { get; } IController Controller { get; set; } - void LoadGame(IGame game); void FrameAdvance(bool render); int Frame { get; } @@ -24,8 +23,6 @@ namespace BizHawk byte[] SaveRam { get; } bool SaveRamModified { get; set; } - // TODO: should IEmulator expose a way of enumerating the Options it understands? - // (the answer is yes) void ResetFrameCounter(); void SaveStateText(TextWriter writer); void LoadStateText(TextReader reader); @@ -33,7 +30,7 @@ namespace BizHawk void LoadStateBinary(BinaryReader reader); byte[] SaveStateBinary(); - //arbitrary extensible core comm mechanism + // Arbitrary extensible core comm mechanism CoreInputComm CoreInputComm { get; set; } CoreOutputComm CoreOutputComm { get; } diff --git a/BizHawk.Emulation/Interfaces/IGame.cs b/BizHawk.Emulation/Interfaces/IGame.cs deleted file mode 100644 index d8efc3db89..0000000000 --- a/BizHawk.Emulation/Interfaces/IGame.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System.Collections.Generic; - -namespace BizHawk -{ - public interface IGame - { - byte[] GetRomData(); - byte[] GetFileData(); - IList GetOptions(); - - //only use this for cosmetic purposes - string Name { get; } - - //use this for path-building purposes - string FilesystemSafeName { get; } - } -} \ No newline at end of file diff --git a/BizHawk.Emulation/QuickCollections.cs b/BizHawk.Emulation/QuickCollections.cs index 20cd7ba92a..877d1e332a 100644 --- a/BizHawk.Emulation/QuickCollections.cs +++ b/BizHawk.Emulation/QuickCollections.cs @@ -1,6 +1,7 @@ using System; +using System.Collections.Generic; -namespace BizHawk.Emulation +namespace BizHawk { // If you're wondering what the point of this is: It's mostly to have .Clear() be fast. // only intended to be used with value types. If used on references you may get GC issues. @@ -84,4 +85,96 @@ namespace BizHawk.Emulation // TODO serialization functions } -} + + // .net has no built-in read only dictionary + public class ReadOnlyDictionary : IDictionary + { + private IDictionary dict; + + public ReadOnlyDictionary(IDictionary dictionary) + { + dict = dictionary; + } + + public void Add(TKey key, TValue value) + { + throw new InvalidOperationException(); + } + + public bool ContainsKey(TKey key) + { + return dict.ContainsKey(key); + } + + public ICollection Keys + { + get { return dict.Keys; } + } + + public bool Remove(TKey key) + { + throw new InvalidOperationException(); + } + + public bool TryGetValue(TKey key, out TValue value) + { + return dict.TryGetValue(key, out value); + } + + public ICollection Values + { + get { return dict.Values; } + } + + public TValue this[TKey key] + { + get { return dict[key]; } + set { throw new InvalidOperationException(); } + } + + public void Add(KeyValuePair item) + { + throw new InvalidOperationException(); + } + + public void Clear() + { + throw new InvalidOperationException(); + } + + public bool Contains(KeyValuePair item) + { + return dict.Contains(item); + } + + public void CopyTo(KeyValuePair[] array, int arrayIndex) + { + dict.CopyTo(array, arrayIndex); + } + + public int Count + { + get { return dict.Count; } + } + + public bool IsReadOnly + { + get { return true; } + } + + public bool Remove(KeyValuePair item) + { + throw new InvalidOperationException(); + } + + public IEnumerator> GetEnumerator() + { + return dict.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + return ((System.Collections.IEnumerable)dict).GetEnumerator(); + } + } +} \ No newline at end of file diff --git a/BizHawk.MultiClient/BizHawk.MultiClient.csproj b/BizHawk.MultiClient/BizHawk.MultiClient.csproj index 8923d0c560..bb8ef1c295 100644 --- a/BizHawk.MultiClient/BizHawk.MultiClient.csproj +++ b/BizHawk.MultiClient/BizHawk.MultiClient.csproj @@ -244,7 +244,6 @@ Component - Form diff --git a/BizHawk.MultiClient/Global.cs b/BizHawk.MultiClient/Global.cs index 1e34729556..9046443ab6 100644 --- a/BizHawk.MultiClient/Global.cs +++ b/BizHawk.MultiClient/Global.cs @@ -14,7 +14,7 @@ namespace BizHawk.MultiClient public static Config Config; public static IEmulator Emulator; public static CoreInputComm CoreInputComm; - public static RomGame Game; + public static GameInfo Game; public static Controller SMSControls; public static Controller PCEControls; public static Controller GenControls; diff --git a/BizHawk.MultiClient/MainForm.MenuItems.cs b/BizHawk.MultiClient/MainForm.MenuItems.cs index bbfc54d13d..52438c83a3 100644 --- a/BizHawk.MultiClient/MainForm.MenuItems.cs +++ b/BizHawk.MultiClient/MainForm.MenuItems.cs @@ -648,7 +648,7 @@ namespace BizHawk.MultiClient private void screenshotAsToolStripMenuItem_Click(object sender, EventArgs e) { - string path = String.Format(Global.Game.ScreenshotPrefix + ".{0:yyyy-MM-dd HH.mm.ss}.png", DateTime.Now); + string path = String.Format(PathManager.ScreenshotPrefix(Global.Game) + ".{0:yyyy-MM-dd HH.mm.ss}.png", DateTime.Now); SaveFileDialog sfd = new SaveFileDialog(); sfd.InitialDirectory = Path.GetDirectoryName(path); @@ -873,7 +873,7 @@ namespace BizHawk.MultiClient else contextMenuStrip1.Items[7].Enabled = true; - string path = Global.Game.SaveStatePrefix + "." + "QuickSave" + SaveSlot.ToString() + ".State.bak"; + string path = PathManager.SaveStatePrefix(Global.Game) + "." + "QuickSave" + SaveSlot + ".State.bak"; var file = new FileInfo(path); if (file.Exists == true) { @@ -1314,7 +1314,7 @@ namespace BizHawk.MultiClient private void undoSavestateToolStripMenuItem_Click(object sender, EventArgs e) { - string path = Global.Game.SaveStatePrefix + "." + "QuickSave" + SaveSlot.ToString() + ".State"; + string path = PathManager.SaveStatePrefix(Global.Game) + "." + "QuickSave" + SaveSlot + ".State"; SwapBackupSavestate(path); Global.RenderPanel.AddMessage("Save slot " + SaveSlot.ToString() + " restored."); } diff --git a/BizHawk.MultiClient/MainForm.cs b/BizHawk.MultiClient/MainForm.cs index a5ed0a9a31..5907b2d6a4 100644 --- a/BizHawk.MultiClient/MainForm.cs +++ b/BizHawk.MultiClient/MainForm.cs @@ -68,7 +68,7 @@ namespace BizHawk.MultiClient public MainForm(string[] args) { InitializeComponent(); - Global.Game = new NullGame(); + Global.Game = new GameInfo(); if (Global.Config.ShowLogWindow) { LogConsole.ShowConsole(); @@ -838,87 +838,88 @@ namespace BizHawk.MultiClient } IEmulator nextEmulator = null; - RomGame game = null; + RomGame rom = null; + GameInfo game = null; + - if (file.Extension.ToLower() == ".iso") + try { - if (Global.PsxCoreLibrary.IsOpen) - { - PsxCore psx = new PsxCore(Global.PsxCoreLibrary); - nextEmulator = psx; - game = new RomGame(); - var disc = Disc.FromIsoPath(path); - Global.DiscHopper.Clear(); - Global.DiscHopper.Enqueue(disc); - Global.DiscHopper.Insert(); - psx.SetDiscHopper(Global.DiscHopper); - } + + if (file.Extension.ToLower() == ".iso") + { + if (Global.PsxCoreLibrary.IsOpen) + { + // sorry zero ;'( I leave de-RomGameifying this to you + //PsxCore psx = new PsxCore(Global.PsxCoreLibrary); + //nextEmulator = psx; + //game = new RomGame(); + //var disc = Disc.FromIsoPath(path); + //Global.DiscHopper.Clear(); + //Global.DiscHopper.Enqueue(disc); + //Global.DiscHopper.Insert(); + //psx.SetDiscHopper(Global.DiscHopper); + } + } + else + { + rom = new RomGame(file); + game = rom.GameInfo; + + switch (game.System) + { + case "SMS": + case "SG": + if (Global.Config.SmsEnableFM) game.AddOption("UseFM"); + if (Global.Config.SmsAllowOverlock) game.AddOption("AllowOverclock"); + if (Global.Config.SmsForceStereoSeparation) game.AddOption("ForceStereo"); + nextEmulator = new SMS(game, rom.RomData); + break; + case "GG": + if (Global.Config.SmsAllowOverlock) game.AddOption("AllowOverclock"); + nextEmulator = new SMS(game, rom.RomData); + break; + case "PCE": + case "SGX": + nextEmulator = new PCEngine(game, rom.RomData); + break; + case "GEN": + nextEmulator = new Genesis(true); //TODO + break; + case "TI83": + nextEmulator = new TI83(game, rom.RomData); + if (Global.Config.TI83autoloadKeyPad) + LoadTI83KeyPad(); + break; + case "NES": + { + NES nes = new NES(game, rom.FileData); + Global.Game.Status = nes.RomStatus; + nextEmulator = nes; + if (Global.Config.NESAutoLoadPalette && Global.Config.NESPaletteFile.Length > 0 && + HawkFile.ExistsAt(Global.Config.NESPaletteFile)) + { + nes.SetPalette( + NES.Palettes.Load_FCEUX_Palette(HawkFile.ReadAllBytes(Global.Config.NESPaletteFile))); + } + } + break; + case "GB": + nextEmulator = new Gameboy(); + break; + } + } + + if (nextEmulator == null) + throw new Exception(); + nextEmulator.CoreInputComm = Global.CoreInputComm; } - else + catch (Exception ex) { - game = new RomGame(file); - - switch (game.System) - { - case "SG": - case "SMS": - nextEmulator = new SMS(); - if (Global.Config.SmsEnableFM) game.AddOptions("UseFM"); - if (Global.Config.SmsAllowOverlock) game.AddOptions("AllowOverclock"); - if (Global.Config.SmsForceStereoSeparation) game.AddOptions("ForceStereo"); - break; - case "GG": - nextEmulator = new SMS { IsGameGear = true }; - if (Global.Config.SmsAllowOverlock) game.AddOptions("AllowOverclock"); - break; - case "PCE": - nextEmulator = new PCEngine(NecSystemType.TurboGrafx); - break; - case "SGX": - nextEmulator = new PCEngine(NecSystemType.SuperGrafx); - break; - case "GEN": - nextEmulator = new Genesis(true);//TODO - break; - case "TI83": - nextEmulator = new TI83(); - if (Global.Config.TI83autoloadKeyPad) - LoadTI83KeyPad(); - break; - case "NES": - { - NES nes = new NES(); - nextEmulator = nes; - if (Global.Config.NESAutoLoadPalette && Global.Config.NESPaletteFile.Length > 0 && HawkFile.ExistsAt(Global.Config.NESPaletteFile)) - { - nes.SetPalette(NES.Palettes.Load_FCEUX_Palette(HawkFile.ReadAllBytes(Global.Config.NESPaletteFile))); - } - } - break; - case "GB": - nextEmulator = new Gameboy(); - break; - } - - if (nextEmulator == null) throw new Exception(); - - try - { - nextEmulator.CoreInputComm = Global.CoreInputComm; - - //this is a bit hacky, but many cores do not take responsibility for setting this, so we need to set it for them. - nextEmulator.CoreOutputComm.RomStatus = game.Status; - - nextEmulator.LoadGame(game); - } - catch (Exception ex) - { - MessageBox.Show("Exception during loadgame:\n\n" + ex.ToString()); - return false; - } + MessageBox.Show("Exception during loadgame:\n\n" + ex.ToString()); + return false; } - + if (nextEmulator == null) throw new Exception(); @@ -936,7 +937,7 @@ namespace BizHawk.MultiClient Text = DisplayNameForSystem(game.System) + " - " + game.Name; ResetRewindBuffer(); Global.Config.RecentRoms.Add(file.CanonicalFullPath); - if (File.Exists(game.SaveRamPath)) + if (File.Exists(PathManager.SaveRamPath(game))) LoadSaveRam(); //setup the throttle based on platform's specifications @@ -975,7 +976,7 @@ namespace BizHawk.MultiClient if (Global.Emulator == null) return; if (Global.Game == null) return; - var status = Global.Emulator.CoreOutputComm.RomStatus; + var status = Global.Game.Status; string annotation = ""; if (status == RomStatus.BadDump) { @@ -1022,7 +1023,7 @@ namespace BizHawk.MultiClient { try { - using (var reader = new BinaryReader(new FileStream(Global.Game.SaveRamPath, FileMode.Open, FileAccess.Read))) + using (var reader = new BinaryReader(new FileStream(PathManager.SaveRamPath(Global.Game), FileMode.Open, FileAccess.Read))) reader.Read(Global.Emulator.SaveRam, 0, Global.Emulator.SaveRam.Length); } catch { } } @@ -1030,25 +1031,27 @@ namespace BizHawk.MultiClient private void CloseGame() { if (Global.Emulator.SaveRamModified) - { - string path = Global.Game.SaveRamPath; - - var f = new FileInfo(path); - if (f.Directory.Exists == false) - f.Directory.Create(); - - var writer = new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.Write)); - int len = Util.SaveRamBytesUsed(Global.Emulator.SaveRam); - //int len = Global.Emulator.SaveRam.Length; - writer.Write(Global.Emulator.SaveRam, 0, len); - writer.Close(); - } + SaveRam(); Global.Emulator.Dispose(); Global.Emulator = new NullEmulator(); Global.ActiveController = Global.NullControls; UserMovie.StopMovie(); } + private static void SaveRam() + { + string path = PathManager.SaveRamPath(Global.Game); + + var f = new FileInfo(path); + if (f.Directory.Exists == false) + f.Directory.Create(); + + var writer = new BinaryWriter(new FileStream(path, FileMode.Create, FileAccess.Write)); + int len = Util.SaveRamBytesUsed(Global.Emulator.SaveRam); + writer.Write(Global.Emulator.SaveRam, 0, len); + writer.Close(); + } + void OnSelectSlot(int num) { SaveSlot = num; @@ -1559,12 +1562,12 @@ namespace BizHawk.MultiClient private void TakeScreenshot() { - MakeScreenshot(String.Format(Global.Game.ScreenshotPrefix + ".{0:yyyy-MM-dd HH.mm.ss}.png", DateTime.Now)); + MakeScreenshot(String.Format(PathManager.ScreenshotPrefix(Global.Game) + ".{0:yyyy-MM-dd HH.mm.ss}.png", DateTime.Now)); } private void SaveState(string name) { - string path = Global.Game.SaveStatePrefix + "." + name + ".State"; + string path = PathManager.SaveStatePrefix(Global.Game) + "." + name + ".State"; var file = new FileInfo(path); if (file.Directory.Exists == false) @@ -1596,7 +1599,7 @@ namespace BizHawk.MultiClient private void SaveStateAs() { var sfd = new SaveFileDialog(); - string path = Global.Game.SaveStatePrefix; + string path = PathManager.SaveStatePrefix(Global.Game); sfd.InitialDirectory = path; sfd.FileName = "QuickSave0.State"; var file = new FileInfo(path); @@ -1629,7 +1632,7 @@ namespace BizHawk.MultiClient private void LoadState(string name) { - string path = Global.Game.SaveStatePrefix + "." + name + ".State"; + string path = PathManager.SaveStatePrefix(Global.Game) + "." + name + ".State"; if (File.Exists(path) == false) return; @@ -1639,7 +1642,7 @@ namespace BizHawk.MultiClient private void LoadStateAs() { var ofd = new OpenFileDialog(); - ofd.InitialDirectory = Global.Game.SaveStatePrefix; + ofd.InitialDirectory = PathManager.SaveStatePrefix(Global.Game); ofd.Filter = "Save States (*.State)|*.State|All Files|*.*"; ofd.RestoreDirectory = true; @@ -1943,7 +1946,7 @@ namespace BizHawk.MultiClient { CloseGame(); Global.Emulator = new NullEmulator(); - Global.Game = new NullGame(); + Global.Game = new GameInfo(); MemoryPulse.Clear(); RamSearch1.Restart(); RamWatch1.Restart(); @@ -2128,7 +2131,7 @@ namespace BizHawk.MultiClient var sfd = new SaveFileDialog(); if (!(Global.Emulator is NullEmulator)) { - sfd.FileName = Global.Game.FilesystemSafeName; + sfd.FileName = PathManager.FilesystemSafeName(Global.Game); sfd.InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.AVIPath, ""); } else diff --git a/BizHawk.MultiClient/NullGame.cs b/BizHawk.MultiClient/NullGame.cs deleted file mode 100644 index ca6b776feb..0000000000 --- a/BizHawk.MultiClient/NullGame.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; - -namespace BizHawk.MultiClient -{ - public class NullGame : RomGame - { - private List options; - private const int BankSize = 4096; - new public RomStatus Status { get; private set; } - new public string Name { get { return "Null Game"; } set { } } - new public string FilesystemSafeName { get { return "Null Game"; } } - - public NullGame() - { - FileData = new byte[1]; - FileData[0] = new byte(); - RomData = new byte[1]; - RomData[0] = new byte(); - System = "Null"; - Status = RomStatus.GoodDump; - options = new List(); - options.Add("null"); - } - - private byte[] DeInterleaveSMD(byte[] source) - { - return FileData; - } - - private void CheckForPatchOptions() - { - } - - new public string SaveRamPath - { - get - { - return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.BasePath, ""), "Null Game.SaveRAM"); - } - } - - - - new public string SaveStatePrefix - { - get - { - string Bind = ""; - if (Global.Config.BindSavestatesToMovies && Global.MainForm.UserMovie.Mode != MOVIEMODE.INACTIVE) - Bind += " - " + Path.GetFileNameWithoutExtension(Global.MainForm.UserMovie.Filename); - - return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.BasePath, ""), "Null Game" + Bind); - } - } - - new public string MoviePrefix - { - get - { - return PathManager.MakeAbsolutePath(Global.Config.BasePath, "") + "Null Game"; - } - } - - new public string ScreenshotPrefix - { - get - { - return PathManager.MakeAbsolutePath(Global.Config.BasePath, "") + "/" + "Null Game"; - } - } - } -} diff --git a/BizHawk.MultiClient/PlayMovie.cs b/BizHawk.MultiClient/PlayMovie.cs index 7234918d1b..308c007d9e 100644 --- a/BizHawk.MultiClient/PlayMovie.cs +++ b/BizHawk.MultiClient/PlayMovie.cs @@ -193,7 +193,7 @@ namespace BizHawk.MultiClient //Pull out matching names for (int x = 0; x < MovieList.Count; x++) { - if (Global.Game.FilesystemSafeName == MovieList[x].GetGameName()) + if (PathManager.FilesystemSafeName(Global.Game) == MovieList[x].GetGameName()) Indexes.Add(x); } if (Indexes.Count == 0) return; diff --git a/BizHawk.MultiClient/RecordMovie.cs b/BizHawk.MultiClient/RecordMovie.cs index 1d891f2e38..5429cfe9a8 100644 --- a/BizHawk.MultiClient/RecordMovie.cs +++ b/BizHawk.MultiClient/RecordMovie.cs @@ -59,7 +59,7 @@ namespace BizHawk.MultiClient MovieToRecord.Header.SetHeaderLine(MovieHeader.GUID, MovieHeader.MakeGUID()); MovieToRecord.Header.SetHeaderLine(MovieHeader.PLATFORM, Global.Emulator.SystemId); if (Global.Game != null) - MovieToRecord.Header.SetHeaderLine(MovieHeader.GAMENAME, Global.Game.FilesystemSafeName); + MovieToRecord.Header.SetHeaderLine(MovieHeader.GAMENAME, PathManager.FilesystemSafeName(Global.Game)); else MovieToRecord.Header.SetHeaderLine(MovieHeader.GAMENAME, "NULL"); @@ -111,7 +111,7 @@ namespace BizHawk.MultiClient SaveFileDialog sfd = new SaveFileDialog(); sfd.InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.MoviesPath, ""); sfd.DefaultExt = ".tas"; - sfd.FileName = Global.Game.FilesystemSafeName; + sfd.FileName = PathManager.FilesystemSafeName(Global.Game); sfd.Filter = "Movie files (*.tas)|*.tas"; Global.Sound.StopSound(); diff --git a/BizHawk.MultiClient/RomGame.cs b/BizHawk.MultiClient/RomGame.cs index 309357e2c7..ace16a0ce9 100644 --- a/BizHawk.MultiClient/RomGame.cs +++ b/BizHawk.MultiClient/RomGame.cs @@ -1,20 +1,14 @@ using System; -using System.Collections.Generic; using System.Globalization; -using System.IO; namespace BizHawk.MultiClient { - public class RomGame : IGame + public class RomGame { public byte[] RomData; public byte[] FileData; - public string System; - public RomStatus Status { get; private set; } + public GameInfo GameInfo; - private string name; - private string filesystemSafeName; - private List options; private const int BankSize = 4096; public RomGame() { } @@ -40,18 +34,10 @@ namespace BizHawk.MultiClient if (file.Extension == ".SMD") RomData = DeInterleaveSMD(RomData); - var info = Database.GetGameInfo(RomData, file.Name); - name = info.Name; - System = info.System; - Status = info.Status; - options = new List(info.GetOptions()); + GameInfo = Database.GetGameInfo(RomData, file.Name); + CheckForPatchOptions(); - //build a safe filesystem name for use in auxilary files (savestates, saveram, etc) - filesystemSafeName = file.CanonicalName.Replace("|", "+"); - filesystemSafeName = Path.Combine(Path.GetDirectoryName(filesystemSafeName), Path.GetFileNameWithoutExtension(filesystemSafeName)); - - if (patch != null) { using (var patchFile = new HawkFile(patch)) @@ -63,12 +49,7 @@ namespace BizHawk.MultiClient } } - public void AddOptions(params string[] options) - { - this.options.AddRange(options); - } - - private byte[] DeInterleaveSMD(byte[] source) + private static byte[] DeInterleaveSMD(byte[] source) { // SMD files are interleaved in pages of 16k, with the first 8k containing all // odd bytes and the second 8k containing all even bytes. @@ -93,113 +74,19 @@ namespace BizHawk.MultiClient { try { - foreach (var opt in options) + if (GameInfo["PatchBytes"]) { - if (opt.StartsWith("PatchBytes")) + string args = GameInfo.OptionValue("PatchBytes"); + foreach (var val in args.Split(',')) { - var split1 = opt.Split('='); - foreach (var val in split1[1].Split(',')) - { - var split3 = val.Split(':'); - int offset = int.Parse(split3[0], NumberStyles.HexNumber); - byte value = byte.Parse(split3[1], NumberStyles.HexNumber); - RomData[offset] = value; - } + var split = val.Split(':'); + int offset = int.Parse(split[0], NumberStyles.HexNumber); + byte value = byte.Parse(split[1], NumberStyles.HexNumber); + RomData[offset] = value; } } } catch (Exception) { } // No need for errors in patching to propagate. } - - public byte[] GetRomData() { return RomData; } - public byte[] GetFileData() { return FileData; } - public IList GetOptions() { return options; } - public string Name { get { return name; } set { name = value; } } - public string FilesystemSafeName { get { return filesystemSafeName; } } - - public string SaveRamPath - { - get - { - switch (System) - { - case "SMS": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathSMSSaveRAM, "SMS"), filesystemSafeName + ".SaveRAM"); - case "GG": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathGGSaveRAM, "GG"), filesystemSafeName + ".SaveRAM"); - case "SG": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathSGSaveRAM, "SG"), filesystemSafeName + ".SaveRAM"); - case "SGX": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathPCESaveRAM, "PCE"), filesystemSafeName + ".SaveRAM"); - case "PCE": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathPCESaveRAM, "PCE"), filesystemSafeName + ".SaveRAM"); - case "GB": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathGBSaveRAM, "GB"), filesystemSafeName + ".SaveRAM"); - case "GEN": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathGenesisSaveRAM, "GEN"), filesystemSafeName + ".SaveRAM"); - case "NES": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathNESSaveRAM, "NES"), filesystemSafeName + ".SaveRAM"); - case "TI83": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathTI83SaveRAM, "TI83"), filesystemSafeName + ".SaveRAM"); - default: return ""; - } - } - } - - public string SaveStatePrefix - { - get - { - string Bind = ""; - if (Global.Config.BindSavestatesToMovies && Global.MainForm.UserMovie.Mode != MOVIEMODE.INACTIVE) - Bind += " - " + Path.GetFileNameWithoutExtension(Global.MainForm.UserMovie.Filename); - switch (System) - { - case "SMS": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathSMSSavestates, "SMS"), filesystemSafeName + Bind); - case "GG": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathGGSavestates, "GG"), filesystemSafeName + Bind); - case "SG": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathSGSavestates, "SG"), filesystemSafeName + Bind); - case "PCE": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathPCESavestates, "PCE"), filesystemSafeName + Bind); - case "SGX": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathPCESavestates, "PCE"), filesystemSafeName + Bind); - case "GB": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathGBSavestates, "GB"), filesystemSafeName + Bind); - case "GEN": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathGenesisSavestates, "GEN"), filesystemSafeName + Bind); - case "NES": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathNESSavestates, "NES"), filesystemSafeName + Bind); - case "TI83": return Path.Combine(PathManager.MakeAbsolutePath(Global.Config.PathTI83Savestates, "TI83"), filesystemSafeName + Bind); - default: return ""; - } - - } - } - - public string MoviePrefix - { - //Obsolete because there is one singular Movie path - get - { - switch (System) - { - case "SMS": return "SMS/Movie/" + filesystemSafeName; - case "GG": return "Game Gear/Movie/" + filesystemSafeName; - case "SG": return "SG-1000/Movie/" + filesystemSafeName; - case "PCE": return "TurboGrafx/Movie/" + filesystemSafeName; - case "SGX": return "TurboGrafx/Movie/" + filesystemSafeName; - case "GB": return "Gameboy/Movie/" + filesystemSafeName; - case "GEN": return "Genesis/Movie/" + filesystemSafeName; - case "NES": return "NES/Movie/" + filesystemSafeName; - case "TI83": return "TI83/Movie/" + filesystemSafeName; - default: return ""; - } - } - } - - public string ScreenshotPrefix - { - get - { - switch (System) - { - case "SMS": return PathManager.MakeAbsolutePath(Global.Config.PathSMSScreenshots, "SMS") + "/" + filesystemSafeName; - case "GG": return PathManager.MakeAbsolutePath(Global.Config.PathGGScreenshots, "GG") + "/" + filesystemSafeName; - case "SG": return PathManager.MakeAbsolutePath(Global.Config.PathSGScreenshots, "SG") + "/" + filesystemSafeName; - case "PCE": return PathManager.MakeAbsolutePath(Global.Config.PathPCEScreenshots, "PCE") + "/" + filesystemSafeName; - case "SGX": return PathManager.MakeAbsolutePath(Global.Config.PathPCEScreenshots, "PCE") + "/" + filesystemSafeName; - case "GB": return PathManager.MakeAbsolutePath(Global.Config.PathGBScreenshots, "GB") + "/" + filesystemSafeName; - case "GEN": return PathManager.MakeAbsolutePath(Global.Config.PathGenesisScreenshots, "GEN") + "/" + filesystemSafeName; - case "NES": return PathManager.MakeAbsolutePath(Global.Config.PathNESScreenshots, "NES") + "/" + filesystemSafeName; - case "TI83": return PathManager.MakeAbsolutePath(Global.Config.PathTI83Screenshots, "TI83") + "/" + filesystemSafeName; - default: return ""; - } - } - } } } diff --git a/BizHawk.MultiClient/SavestateManager.cs b/BizHawk.MultiClient/SavestateManager.cs index 36f8155a0c..940ff3c8d0 100644 --- a/BizHawk.MultiClient/SavestateManager.cs +++ b/BizHawk.MultiClient/SavestateManager.cs @@ -27,7 +27,7 @@ namespace BizHawk.MultiClient } for (int x = 0; x < 10; x++) { - path = Global.Game.SaveStatePrefix + "." + "QuickSave" + x + ".State"; + path = PathManager.SaveStatePrefix(Global.Game) + "." + "QuickSave" + x + ".State"; var file = new FileInfo(path); if (file.Directory.Exists == false) file.Directory.Create(); diff --git a/BizHawk.MultiClient/config/PathManager.cs b/BizHawk.MultiClient/config/PathManager.cs index 5666e8e0b8..c1a02bb32b 100644 --- a/BizHawk.MultiClient/config/PathManager.cs +++ b/BizHawk.MultiClient/config/PathManager.cs @@ -259,5 +259,65 @@ namespace BizHawk.MultiClient return path; } + + public static string FilesystemSafeName(GameInfo game) + { + string filesystemSafeName = game.Name.Replace("|", "+"); + return Path.Combine(Path.GetDirectoryName(filesystemSafeName), Path.GetFileNameWithoutExtension(filesystemSafeName)); + } + + public static string SaveRamPath(GameInfo game) + { + string name = FilesystemSafeName(game); + switch (game.System) + { + case "SMS": return Path.Combine(MakeAbsolutePath(Global.Config.PathSMSSaveRAM, "SMS"), name + ".SaveRAM"); + case "GG": return Path.Combine(MakeAbsolutePath(Global.Config.PathGGSaveRAM, "GG"), name + ".SaveRAM"); + case "SG": return Path.Combine(MakeAbsolutePath(Global.Config.PathSGSaveRAM, "SG"), name + ".SaveRAM"); + case "SGX": return Path.Combine(MakeAbsolutePath(Global.Config.PathPCESaveRAM, "PCE"), name + ".SaveRAM"); + case "PCE": return Path.Combine(MakeAbsolutePath(Global.Config.PathPCESaveRAM, "PCE"), name + ".SaveRAM"); + case "GB": return Path.Combine(MakeAbsolutePath(Global.Config.PathGBSaveRAM, "GB"), name + ".SaveRAM"); + case "GEN": return Path.Combine(MakeAbsolutePath(Global.Config.PathGenesisSaveRAM, "GEN"), name + ".SaveRAM"); + case "NES": return Path.Combine(MakeAbsolutePath(Global.Config.PathNESSaveRAM, "NES"), name + ".SaveRAM"); + case "TI83": return Path.Combine(MakeAbsolutePath(Global.Config.PathTI83SaveRAM, "TI83"), name + ".SaveRAM"); + } + return ""; + } + + public static string SaveStatePrefix(GameInfo game) + { + string name = FilesystemSafeName(game); + switch (game.System) + { + case "SMS": return Path.Combine(MakeAbsolutePath(Global.Config.PathSMSSavestates, "SMS"), name); + case "GG": return Path.Combine(MakeAbsolutePath(Global.Config.PathGGSavestates, "GG"), name); + case "SG": return Path.Combine(MakeAbsolutePath(Global.Config.PathSGSavestates, "SG"), name); + case "SGX": return Path.Combine(MakeAbsolutePath(Global.Config.PathPCESavestates, "PCE"), name); + case "PCE": return Path.Combine(MakeAbsolutePath(Global.Config.PathPCESavestates, "PCE"), name); + case "GB": return Path.Combine(MakeAbsolutePath(Global.Config.PathGBSavestates, "GB"), name); + case "GEN": return Path.Combine(MakeAbsolutePath(Global.Config.PathGenesisSavestates, "GEN"), name); + case "NES": return Path.Combine(MakeAbsolutePath(Global.Config.PathNESSavestates, "NES"), name); + case "TI83": return Path.Combine(MakeAbsolutePath(Global.Config.PathTI83Savestates, "TI83"), name); + } + return ""; + } + + public static string ScreenshotPrefix(GameInfo game) + { + string name = FilesystemSafeName(game); + switch (game.System) + { + case "SMS": return Path.Combine(MakeAbsolutePath(Global.Config.PathSMSScreenshots, "SMS"), name); + case "GG": return Path.Combine(MakeAbsolutePath(Global.Config.PathGGScreenshots, "GG"), name); + case "SG": return Path.Combine(MakeAbsolutePath(Global.Config.PathSGScreenshots, "SG"), name); + case "SGX": return Path.Combine(MakeAbsolutePath(Global.Config.PathPCEScreenshots, "PCE"), name); + case "PCE": return Path.Combine(MakeAbsolutePath(Global.Config.PathPCEScreenshots, "PCE"), name); + case "GB": return Path.Combine(MakeAbsolutePath(Global.Config.PathGBScreenshots, "GB"), name); + case "GEN": return Path.Combine(MakeAbsolutePath(Global.Config.PathGenesisScreenshots, "GEN"), name); + case "NES": return Path.Combine(MakeAbsolutePath(Global.Config.PathNESScreenshots, "NES"), name); + case "TI83": return Path.Combine(MakeAbsolutePath(Global.Config.PathTI83Screenshots, "TI83"), name); + } + return ""; + } } } diff --git a/BizHawk.MultiClient/tools/Cheats.cs b/BizHawk.MultiClient/tools/Cheats.cs index d35a6a0d2a..2fcb3b6a3d 100644 --- a/BizHawk.MultiClient/tools/Cheats.cs +++ b/BizHawk.MultiClient/tools/Cheats.cs @@ -58,7 +58,7 @@ namespace BizHawk.MultiClient private string MakeDefaultFilename() { - return Path.Combine(GetCheatsPath(), Global.Game.FilesystemSafeName + ".cht"); + return Path.Combine(GetCheatsPath(), PathManager.FilesystemSafeName(Global.Game) + ".cht"); } private void ClearFields() @@ -397,7 +397,7 @@ namespace BizHawk.MultiClient if (currentCheatFile.Length > 0) sfd.FileName = Path.GetFileNameWithoutExtension(currentCheatFile); else if (!(Global.Emulator is NullEmulator)) - sfd.FileName = Global.Game.FilesystemSafeName; + sfd.FileName = PathManager.FilesystemSafeName(Global.Game); sfd.InitialDirectory = GetCheatsPath(); sfd.Filter = "Cheat Files (*.cht)|*.cht|All Files|*.*"; sfd.RestoreDirectory = true; diff --git a/BizHawk.MultiClient/tools/RamSearch.cs b/BizHawk.MultiClient/tools/RamSearch.cs index 486dbd3fe1..9d9a90ccab 100644 --- a/BizHawk.MultiClient/tools/RamSearch.cs +++ b/BizHawk.MultiClient/tools/RamSearch.cs @@ -1287,7 +1287,7 @@ namespace BizHawk.MultiClient } else if (!(Global.Emulator is NullEmulator)) { - sfd.FileName = Global.Game.FilesystemSafeName; + sfd.FileName = PathManager.FilesystemSafeName(Global.Game); sfd.InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.WatchPath, ""); } else diff --git a/BizHawk.MultiClient/tools/RamWatch.cs b/BizHawk.MultiClient/tools/RamWatch.cs index 46a1ad326c..fc3f11a5e9 100644 --- a/BizHawk.MultiClient/tools/RamWatch.cs +++ b/BizHawk.MultiClient/tools/RamWatch.cs @@ -659,7 +659,7 @@ namespace BizHawk.MultiClient } else if (!(Global.Emulator is NullEmulator)) { - sfd.FileName = Global.Game.FilesystemSafeName; + sfd.FileName = PathManager.FilesystemSafeName(Global.Game); sfd.InitialDirectory = PathManager.MakeAbsolutePath(Global.Config.WatchPath, ""); } else