Skip to content

Commit

Permalink
SNES carts database
Browse files Browse the repository at this point in the history
  • Loading branch information
ClusterM committed Oct 7, 2017
1 parent 0ceac8f commit ef067b9
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 6 deletions.
5 changes: 2 additions & 3 deletions Apps/NesGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ public static void LoadCache()
{
try
{
var xmlDataBasePath = System.IO.Path.Combine(System.IO.Path.Combine(Program.BaseDirectoryInternal, "data"), "nescarts.xml");
var xmlDataBasePath = Path.Combine(System.IO.Path.Combine(Program.BaseDirectoryInternal, "data"), "nescarts.xml");
Debug.WriteLine("Loading " + xmlDataBasePath);

if (File.Exists(xmlDataBasePath))
Expand Down Expand Up @@ -219,14 +219,13 @@ public static void LoadCache()
};
}
}
Debug.WriteLine(string.Format("XML loading done, {0} roms total", gameInfoCache.Count));
Debug.WriteLine(string.Format("NES XML loading done, {0} roms total", gameInfoCache.Count));
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + ex.StackTrace);
}
}

}
}

116 changes: 113 additions & 3 deletions Apps/SnesGame.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@
using com.clusterrr.hakchi_gui.Properties;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
using System.Xml.XPath;

namespace com.clusterrr.hakchi_gui
{
public class SnesGame : NesMiniApplication
public class SnesGame : NesMiniApplication, ICloverAutofill
{
public enum SnesRomType { LoRom = 0x14, HiRom = 0x15 };

const string DefaultArgs = "--volume 100 -rollback-snapshot-period 600";
static List<byte> SfxTypes = new List<byte>() { 0x13, 0x14, 0x15, 0x1a };
static List<byte> Dsp1Types = new List<byte>() { 0x03, 0x05 };
Expand Down Expand Up @@ -65,6 +69,7 @@ public class SnesGame : NesMiniApplication
{ "MEGAMAN X3", 0x113D },
{ "Breath of Fire", 0x1144 },
};
private static Dictionary<uint, CachedGameInfo> gameInfoCache = null;

public override string GoogleSuffix
{
Expand Down Expand Up @@ -96,7 +101,9 @@ public static bool Patch(string inputFileName, ref byte[] rawRomData, ref char p
var stripped = new byte[rawRomData.Length - 512];
Array.Copy(rawRomData, 512, stripped, 0, stripped.Length);
rawRomData = stripped;
crc32 = CRC32(rawRomData);
}
Debug.WriteLine($"Trying to convert {inputFileName}");
MakeSfrom(ref rawRomData, ref saveCount);
outputFileName = Path.GetFileNameWithoutExtension(outputFileName) + ".sfrom";
}
Expand Down Expand Up @@ -135,29 +142,46 @@ private static void MakeSfrom(ref byte[] rawRomData, ref byte saveCount)
romType = SnesRomType.HiRom;
romHeader = romHeaderHiRom;
}
else if ((romHeaderLoRom.RomMakeup & 1) == 0)
else if (((romHeaderLoRom.RomMakeup & 1) == 0) && ((romHeaderHiRom.RomMakeup & 1) == 0))
{
romType = SnesRomType.LoRom;
romHeader = romHeaderLoRom;
}
else if (((romHeaderLoRom.RomMakeup & 1) == 1) && ((romHeaderHiRom.RomMakeup & 1) == 1))
{
romType = SnesRomType.HiRom;
romHeader = romHeaderHiRom;
}
else
{
// WTF is it?
romType = SnesRomType.HiRom;
romHeader = romHeaderHiRom;
}

string gameTitle = romHeader.GameTitle.Trim();
Debug.WriteLine($"Game title: {gameTitle}");
ushort presetId = 0; // 0x1011;
ushort chip = 0;
if (SfxTypes.Contains(romHeader.RomType)) // Super FX chip
{
Debug.WriteLine($"Super FX chip detected");
chip = 0x0C;
}
if (!knownPresets.TryGetValue(gameTitle, out presetId)) // Known codes
{
if (Dsp1Types.Contains(romHeader.RomType))
{
Debug.WriteLine($"DSP-1 chip detected");
presetId = 0x10BD; // ID from Mario Kard, DSP1
}
if (SA1Types.Contains(romHeader.RomType))
{
Debug.WriteLine($"SA1 chip detected");
presetId = 0x109C; // ID from Super Mario RPG, SA1
}
}
Debug.WriteLine(string.Format("PresetID: 0x{0:X2}{1:X2}, extra byte: {2:X2}", presetId & 0xFF, (presetId >> 8) & 0xFF, chip));

var sfromHeader1 = new SfromHeader1((uint)rawRomData.Length);
var sfromHeader2 = new SfromHeader2((uint)rawRomData.Length, presetId, romType, chip);
Expand Down Expand Up @@ -407,7 +431,93 @@ public static SfromHeader2 Read(byte[] buffer, int pos)
}
}

public enum SnesRomType { LoRom = 0x14, HiRom = 0x15 };
private struct CachedGameInfo
{
public string Name;
public byte Players;
public bool Simultaneous;
public string ReleaseDate;
public string Publisher;
public string Region;
}

public static void LoadCache()
{
try
{
var xmlDataBasePath = Path.Combine(System.IO.Path.Combine(Program.BaseDirectoryInternal, "data"), "snescarts.xml");
Debug.WriteLine("Loading " + xmlDataBasePath);

if (File.Exists(xmlDataBasePath))
{
var xpath = new XPathDocument(xmlDataBasePath);
var navigator = xpath.CreateNavigator();
var iterator = navigator.Select("/Data");
gameInfoCache = new Dictionary<uint, CachedGameInfo>();
while (iterator.MoveNext())
{
XPathNavigator game = iterator.Current;
var cartridges = game.Select("Game");
while (cartridges.MoveNext())
{
var cartridge = cartridges.Current;
uint crc = 0;
var info = new CachedGameInfo();

try
{
var v = cartridge.Select("name");
if (v.MoveNext() && !string.IsNullOrEmpty(v.Current.Value))
info.Name = v.Current.Value;
v = cartridge.Select("players");
if (v.MoveNext() && !string.IsNullOrEmpty(v.Current.Value))
info.Players = byte.Parse(v.Current.Value);
v = cartridge.Select("simultaneous");
if (v.MoveNext() && !string.IsNullOrEmpty(v.Current.Value))
info.Simultaneous = byte.Parse(v.Current.Value) != 0;
v = cartridge.Select("crc");
if (v.MoveNext() && !string.IsNullOrEmpty(v.Current.Value))
crc = Convert.ToUInt32(v.Current.Value, 16);
v = cartridge.Select("date");
if (v.MoveNext() && !string.IsNullOrEmpty(v.Current.Value))
info.ReleaseDate = v.Current.Value;
v = cartridge.Select("publisher");
if (v.MoveNext() && !string.IsNullOrEmpty(v.Current.Value))
info.Publisher = v.Current.Value;
}
catch
{
Debug.WriteLine($"Invalid XML record for game: {cartridge.OuterXml}");
}

gameInfoCache[crc] = info;
};
}
}
Debug.WriteLine(string.Format("SNES XML loading done, {0} roms total", gameInfoCache.Count));
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message + ex.StackTrace);
}
}

public bool TryAutofill(uint crc32)
{
CachedGameInfo gameinfo;
if (gameInfoCache != null && gameInfoCache.TryGetValue(crc32, out gameinfo))
{
Name = gameinfo.Name;
Players = gameinfo.Players;
Simultaneous = gameinfo.Simultaneous;
ReleaseDate = gameinfo.ReleaseDate;
if (ReleaseDate.Length == 4) ReleaseDate += "-01";
if (ReleaseDate.Length == 7) ReleaseDate += "-01";
Publisher = gameinfo.Publisher.ToUpper();
return true;
}
return false;
}
}
}

1 change: 1 addition & 0 deletions MainForm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ void FormInitialize()

// Loading games database in background
new Thread(NesGame.LoadCache).Start();
new Thread(SnesGame.LoadCache).Start();
// Recalculate games in background
new Thread(RecalculateSelectedGamesThread).Start();

Expand Down
File renamed without changes.
3 changes: 3 additions & 0 deletions hakchi_gui.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -1684,6 +1684,9 @@
<Content Include="data\fes1.bin">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="data\snescarts.xml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
<Content Include="data\splash.gz">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</Content>
Expand Down

0 comments on commit ef067b9

Please sign in to comment.