M-M-M-MONSTER COMMIT! change Game-load api stuff

This commit is contained in:
beirich 2011-08-04 03:20:54 +00:00
parent 788cd17317
commit b27673f26c
29 changed files with 427 additions and 527 deletions

View File

@ -181,6 +181,7 @@
<Compile Include="Consoles\Gameboy\Mappers.cs" />
<Compile Include="Database\CRC32.cs" />
<Compile Include="Database\Database.cs" />
<Compile Include="Database\GameInfo.cs" />
<Compile Include="Disc\CCD_format.cs" />
<Compile Include="Disc\CUE_format.cs" />
<Compile Include="Disc\Disc.API.cs" />
@ -205,7 +206,6 @@
<Compile Include="Sound\Utilities\Metaspu.cs" />
<Compile Include="Interfaces\IController.cs" />
<Compile Include="Interfaces\IEmulator.cs" />
<Compile Include="Interfaces\IGame.cs" />
<Compile Include="Interfaces\ISoundProvider.cs" />
<Compile Include="Interfaces\IVideoProvider.cs" />
<Compile Include="Log.cs" />

View File

@ -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;

View File

@ -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;

View File

@ -215,7 +215,7 @@ namespace BizHawk.Emulation.Consoles.Nintendo
/// </summary>
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
/// <summary>
/// Logical game information. May exist in form of several carts (different revisions)
/// </summary>
public class GameInfo
public class NESGameInfo
{
public string name;
public List<CartInfo> carts = new List<CartInfo>();
@ -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<GameInfo> games = new List<GameInfo>(); //maybe we dont need to track this
List<NESGameInfo> games = new List<NESGameInfo>(); //maybe we dont need to track this
Bag<string, CartInfo> sha1_table = new Bag<string, CartInfo>();
public List<CartInfo> Identify(string sha1)

View File

@ -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)

View File

@ -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;

View File

@ -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();

View File

@ -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()
{

View File

@ -25,7 +25,6 @@ namespace BizHawk.Emulation.Consoles.Sega
public byte[] RomData;
public byte RomBank0, RomBank1, RomBank2;
public byte RomBanks;
public IList<string> 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)

View File

@ -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<string, string> ParseOptionsDictionary()
{
var ret = new Dictionary<string, string>();
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<string, GameInfo> db = new Dictionary<string, GameInfo>();
private static Dictionary<string, CompactGameInfo> db = new Dictionary<string, CompactGameInfo>();
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)));

View File

@ -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;

View File

@ -28,7 +28,6 @@ namespace BizHawk
Frame = 0;
}
public void LoadGame(IGame game) { }
public void FrameAdvance(bool render)
{
if (render == false) return;

View File

@ -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;
}
}

View File

@ -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; }

View File

@ -1,17 +0,0 @@
using System.Collections.Generic;
namespace BizHawk
{
public interface IGame
{
byte[] GetRomData();
byte[] GetFileData();
IList<string> GetOptions();
//only use this for cosmetic purposes
string Name { get; }
//use this for path-building purposes
string FilesystemSafeName { get; }
}
}

View File

@ -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<TKey, TValue> : IDictionary<TKey,TValue>
{
private IDictionary<TKey, TValue> dict;
public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
{
dict = dictionary;
}
public void Add(TKey key, TValue value)
{
throw new InvalidOperationException();
}
public bool ContainsKey(TKey key)
{
return dict.ContainsKey(key);
}
public ICollection<TKey> 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<TValue> Values
{
get { return dict.Values; }
}
public TValue this[TKey key]
{
get { return dict[key]; }
set { throw new InvalidOperationException(); }
}
public void Add(KeyValuePair<TKey, TValue> item)
{
throw new InvalidOperationException();
}
public void Clear()
{
throw new InvalidOperationException();
}
public bool Contains(KeyValuePair<TKey, TValue> item)
{
return dict.Contains(item);
}
public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
dict.CopyTo(array, arrayIndex);
}
public int Count
{
get { return dict.Count; }
}
public bool IsReadOnly
{
get { return true; }
}
public bool Remove(KeyValuePair<TKey, TValue> item)
{
throw new InvalidOperationException();
}
public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return dict.GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return ((System.Collections.IEnumerable)dict).GetEnumerator();
}
}
}

View File

@ -244,7 +244,6 @@
<Compile Include="NEStools\SpriteViewer.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="NullGame.cs" />
<Compile Include="PlayMovie.cs">
<SubType>Form</SubType>
</Compile>

View File

@ -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;

View File

@ -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.");
}

View File

@ -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

View File

@ -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<string> 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<String>();
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";
}
}
}
}

View File

@ -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;

View File

@ -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();

View File

@ -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<string> 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<string>(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<string> 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 "";
}
}
}
}
}

View File

@ -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();

View File

@ -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 "";
}
}
}

View File

@ -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;

View File

@ -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

View File

@ -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