GBS support using SameBoy

This commit is contained in:
CasualPokePlayer 2022-10-03 01:55:14 -07:00
parent 0c6f0523a0
commit 9528a2030f
8 changed files with 148 additions and 13 deletions

Binary file not shown.

Binary file not shown.

View File

@ -10,6 +10,7 @@ using BizHawk.Common.StringExtensions;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores;
using BizHawk.Emulation.Cores.Libretro;
using BizHawk.Emulation.Cores.Nintendo.Sameboy;
using BizHawk.Emulation.Cores.Nintendo.SNES;
using BizHawk.Emulation.Cores.Sony.PSX;
using BizHawk.Emulation.Cores.Arcades.MAME;
@ -493,6 +494,19 @@ namespace BizHawk.Client.Common
nextEmulator = MakeCoreFromCoreInventory(cip, forcedCoreName);
}
private void LoadGBS(string path, CoreComm nextComm, HawkFile file, out IEmulator nextEmulator, out RomGame rom, out GameInfo game)
{
rom = new RomGame(file);
rom.GameInfo.System = VSystemID.Raw.GB;
game = rom.GameInfo;
nextEmulator = new Sameboy(
nextComm,
rom.FileData,
GetCoreSettings<Sameboy, Sameboy.SameboySettings>(),
GetCoreSyncSettings<Sameboy, Sameboy.SameboySyncSettings>()
);
}
private void LoadPSF(string path, CoreComm nextComm, HawkFile file, out IEmulator nextEmulator, out RomGame rom, out GameInfo game)
{
// TODO: Why does the PSF loader need CbDeflater provided? Surely this is a matter internal to it.
@ -679,6 +693,9 @@ namespace BizHawk.Client.Common
if (!LoadXML(path, nextComm, file, forcedCoreName, out nextEmulator, out rom, out game))
return false;
break;
case ".gbs":
LoadGBS(path, nextComm, file, out nextEmulator, out rom, out game);
break;
case ".psf":
case ".minipsf":
LoadPSF(path, nextComm, file, out nextEmulator, out rom, out game);

View File

@ -47,6 +47,25 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
[BizImport(cc)]
public abstract void sameboy_destroy(IntPtr core);
[StructLayout(LayoutKind.Sequential)]
public struct GBSInfo
{
public byte TrackCount;
public byte FirstTrack;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 33)]
public byte[] Title;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 33)]
public byte[] Author;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 33)]
public byte[] Copyright;
}
[BizImport(cc, Compatibility = true)]
public abstract bool sameboy_loadgbs(IntPtr core, byte[] gbs, int gbslen, ref GBSInfo gbsInfo);
[BizImport(cc)]
public abstract void sameboy_switchgbstrack(IntPtr core, int track);
[UnmanagedFunctionPointer(cc)]
public delegate void InputCallback();

View File

@ -15,6 +15,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
private static readonly IReadOnlyList<string> GB_BUTTON_ORDER_IN_BITMASK = new[] { "Start", "Select", "B", "A", "Down", "Up", "Left", "Right", };
private readonly int _firstTrack;
private readonly int _lastTrack;
private int _curTrack = 0;
private bool _switchingTrack = false;
private LibSameboy.Buttons FrameAdvancePrep(IController controller)
{
_controller = controller;
@ -31,6 +36,33 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
LibSameboy.sameboy_reset(SameboyState);
}
var prevTrack = controller.IsPressed("Previous Track");
var nextTrack = controller.IsPressed("Next Track");
if (!_switchingTrack)
{
if (prevTrack)
{
if (_curTrack != _firstTrack)
{
_curTrack--;
LibSameboy.sameboy_switchgbstrack(SameboyState, _curTrack);
Comm.Notify($"Switching to Track {_curTrack}");
}
}
else if (nextTrack)
{
if (_curTrack != _lastTrack)
{
_curTrack++;
LibSameboy.sameboy_switchgbstrack(SameboyState, _curTrack);
Comm.Notify($"Switching to Track {_curTrack}");
}
}
}
_switchingTrack = prevTrack || nextTrack;
IsLagFrame = true;
LibSameboy.sameboy_settracecallback(SameboyState, Tracer.IsEnabled() ? _tracecb : null);

View File

@ -27,6 +27,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
writer.Write(theta_prev);
writer.Write(phi_prev);
writer.Write(phi_prev_2);
writer.Write(_curTrack);
writer.Write(_switchingTrack);
}
public void LoadStateBinary(BinaryReader reader)
@ -55,6 +57,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
theta_prev = reader.ReadDouble();
phi_prev = reader.ReadDouble();
phi_prev_2 = reader.ReadDouble();
_curTrack = reader.ReadInt32();
_switchingTrack = reader.ReadBoolean();
}
public void DebugSameBoyState()

View File

@ -1,5 +1,6 @@
using System;
using System.IO;
using System.Text;
using BizHawk.BizInvoke;
using BizHawk.Common;
@ -29,6 +30,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
private readonly Gameboy.GBDisassembler _disassembler;
private readonly CoreComm Comm;
private IntPtr SameboyState { get; set; } = IntPtr.Zero;
public bool IsCgb { get; set; }
@ -41,14 +44,68 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
private readonly LibSameboy.RumbleCallback _rumblecb;
public Sameboy(CoreComm comm, byte[] gbs, SameboySettings settings, SameboySyncSettings syncSettings)
: this(comm, GameInfo.NullInstance, null, settings, syncSettings, false)
{
var gbsInfo = new LibSameboy.GBSInfo
{
TrackCount = 0,
FirstTrack = 0,
Title = new byte[33],
Author = new byte[33],
Copyright = new byte[33],
};
if (!LibSameboy.sameboy_loadgbs(SameboyState, gbs, gbs.Length, ref gbsInfo))
{
throw new InvalidOperationException("Core rejected the GBS!");
}
RomDetails = $"Track Count: {gbsInfo.TrackCount}\r\n" +
$"First Track: {gbsInfo.FirstTrack}\r\n" +
$"Title: {Encoding.UTF8.GetString(gbsInfo.Title).Trim()}\r\n" +
$"Author: {Encoding.UTF8.GetString(gbsInfo.Author).Trim()}\r\n" +
$"Copyright: {Encoding.UTF8.GetString(gbsInfo.Copyright).Trim()}";
_firstTrack = gbsInfo.FirstTrack;
_lastTrack = gbsInfo.FirstTrack + gbsInfo.TrackCount - 1;
_curTrack = _firstTrack;
LibSameboy.sameboy_switchgbstrack(SameboyState, _curTrack);
BoardName = "GBS";
ControllerDefinition = new ControllerDefinition("GBS Controller")
{
BoolButtons = { "Previous Track", "Next Track" }
}.MakeImmutable();
Comm = comm;
_stateBuf = new byte[LibSameboy.sameboy_statelen(SameboyState)];
}
[CoreConstructor(VSystemID.Raw.GB)]
[CoreConstructor(VSystemID.Raw.GBC)]
public Sameboy(CoreComm comm, GameInfo game, byte[] file, SameboySettings settings, SameboySyncSettings syncSettings, bool deterministic)
public Sameboy(CoreLoadParameters<SameboySettings, SameboySyncSettings> lp)
: this(lp.Comm, lp.Game, lp.Roms[0].FileData, lp.Settings, lp.SyncSettings, lp.DeterministicEmulationRequested)
{
var file = lp.Roms[0].FileData;
RomDetails = $"{lp.Game.Name}\r\n{SHA1Checksum.ComputePrefixedHex(file)}\r\n{MD5Checksum.ComputePrefixedHex(file)}\r\n";
BoardName = MapperName(file);
_hasAcc = BoardName is "MBC7 ROM+ACCEL+EEPROM";
ControllerDefinition = Gameboy.Gameboy.CreateControllerDefinition(sgb: false, sub: false, tilt: _hasAcc, rumble: true, remote: false);
_stateBuf = new byte[LibSameboy.sameboy_statelen(SameboyState)];
}
private Sameboy(CoreComm comm, GameInfo game, byte[] file, SameboySettings settings, SameboySyncSettings syncSettings, bool deterministic)
{
_serviceProvider = new BasicServiceProvider(this);
_settings = settings ?? new SameboySettings();
_syncSettings = syncSettings ?? new SameboySyncSettings();
_settings = settings ?? new();
_syncSettings = syncSettings ?? new();
var model = _syncSettings.ConsoleMode;
if (model is SameboySyncSettings.GBModel.Auto)
@ -86,7 +143,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
DeterministicEmulation = true;
}
SameboyState = LibSameboy.sameboy_create(file, file.Length, bios, bios.Length, model, realtime, _syncSettings.NoJoypadBounce);
SameboyState = LibSameboy.sameboy_create(file, file?.Length ?? 0, bios, bios.Length, model, realtime, _syncSettings.NoJoypadBounce);
InitMemoryDomains();
InitMemoryCallbacks();
@ -111,14 +168,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
PutSettings(_settings);
_stateBuf = new byte[LibSameboy.sameboy_statelen(SameboyState)];
RomDetails = $"{game.Name}\r\n{SHA1Checksum.ComputePrefixedHex(file)}\r\n{MD5Checksum.ComputePrefixedHex(file)}\r\n";
BoardName = MapperName(file);
_hasAcc = BoardName is "MBC7 ROM+ACCEL+EEPROM";
ControllerDefinition = Gameboy.Gameboy.CreateControllerDefinition(sgb: false, sub: false, tilt: _hasAcc, rumble: true, remote: false);
LibSameboy.sameboy_setrtcdivisoroffset(SameboyState, _syncSettings.RTCDivisorOffset);
CycleCount = 0;
}

View File

@ -143,7 +143,11 @@ EXPORT biz_t* sameboy_create(u8* romdata, u32 romlen, u8* biosdata, u32 bioslen,
biz_t* biz = calloc(1, sizeof (biz_t));
GB_random_seed(0);
GB_init(&biz->gb, model);
GB_load_rom_from_buffer(&biz->gb, romdata, romlen);
// this will be NULL if a GBS is going to be loaded later
if (romdata)
{
GB_load_rom_from_buffer(&biz->gb, romdata, romlen);
}
GB_load_boot_rom_from_buffer(&biz->gb, biosdata, bioslen);
GB_set_sample_rate(&biz->gb, GB_get_clock_rate(&biz->gb) / 2 / 8);
GB_set_rumble_mode(&biz->gb, GB_RUMBLE_ALL_GAMES);
@ -171,6 +175,16 @@ EXPORT void sameboy_destroy(biz_t* biz)
free(biz);
}
EXPORT bool sameboy_loadgbs(biz_t* biz, u8* gbs, u32 gbslen, GB_gbs_info_t* gbsinfo)
{
return GB_load_gbs_from_buffer(&biz->gb, gbs, gbslen, gbsinfo) == 0;
}
EXPORT void sameboy_switchgbstrack(biz_t* biz, u32 track)
{
GB_gbs_switch_track(&biz->gb, track);
}
EXPORT void sameboy_setinputcallback(biz_t* biz, input_callback_t callback)
{
biz->input_cb = callback;