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.Common;
using BizHawk.Emulation.Cores; using BizHawk.Emulation.Cores;
using BizHawk.Emulation.Cores.Libretro; using BizHawk.Emulation.Cores.Libretro;
using BizHawk.Emulation.Cores.Nintendo.Sameboy;
using BizHawk.Emulation.Cores.Nintendo.SNES; using BizHawk.Emulation.Cores.Nintendo.SNES;
using BizHawk.Emulation.Cores.Sony.PSX; using BizHawk.Emulation.Cores.Sony.PSX;
using BizHawk.Emulation.Cores.Arcades.MAME; using BizHawk.Emulation.Cores.Arcades.MAME;
@ -493,6 +494,19 @@ namespace BizHawk.Client.Common
nextEmulator = MakeCoreFromCoreInventory(cip, forcedCoreName); 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) 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. // 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)) if (!LoadXML(path, nextComm, file, forcedCoreName, out nextEmulator, out rom, out game))
return false; return false;
break; break;
case ".gbs":
LoadGBS(path, nextComm, file, out nextEmulator, out rom, out game);
break;
case ".psf": case ".psf":
case ".minipsf": case ".minipsf":
LoadPSF(path, nextComm, file, out nextEmulator, out rom, out game); LoadPSF(path, nextComm, file, out nextEmulator, out rom, out game);

View File

@ -47,6 +47,25 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
[BizImport(cc)] [BizImport(cc)]
public abstract void sameboy_destroy(IntPtr core); 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)] [UnmanagedFunctionPointer(cc)]
public delegate void InputCallback(); 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 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) private LibSameboy.Buttons FrameAdvancePrep(IController controller)
{ {
_controller = controller; _controller = controller;
@ -31,6 +36,33 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
LibSameboy.sameboy_reset(SameboyState); 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; IsLagFrame = true;
LibSameboy.sameboy_settracecallback(SameboyState, Tracer.IsEnabled() ? _tracecb : null); 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(theta_prev);
writer.Write(phi_prev); writer.Write(phi_prev);
writer.Write(phi_prev_2); writer.Write(phi_prev_2);
writer.Write(_curTrack);
writer.Write(_switchingTrack);
} }
public void LoadStateBinary(BinaryReader reader) public void LoadStateBinary(BinaryReader reader)
@ -55,6 +57,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
theta_prev = reader.ReadDouble(); theta_prev = reader.ReadDouble();
phi_prev = reader.ReadDouble(); phi_prev = reader.ReadDouble();
phi_prev_2 = reader.ReadDouble(); phi_prev_2 = reader.ReadDouble();
_curTrack = reader.ReadInt32();
_switchingTrack = reader.ReadBoolean();
} }
public void DebugSameBoyState() public void DebugSameBoyState()

View File

@ -1,5 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Text;
using BizHawk.BizInvoke; using BizHawk.BizInvoke;
using BizHawk.Common; using BizHawk.Common;
@ -29,6 +30,8 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
private readonly Gameboy.GBDisassembler _disassembler; private readonly Gameboy.GBDisassembler _disassembler;
private readonly CoreComm Comm;
private IntPtr SameboyState { get; set; } = IntPtr.Zero; private IntPtr SameboyState { get; set; } = IntPtr.Zero;
public bool IsCgb { get; set; } public bool IsCgb { get; set; }
@ -41,14 +44,68 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
private readonly LibSameboy.RumbleCallback _rumblecb; 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.GB)]
[CoreConstructor(VSystemID.Raw.GBC)] [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); _serviceProvider = new BasicServiceProvider(this);
_settings = settings ?? new SameboySettings(); _settings = settings ?? new();
_syncSettings = syncSettings ?? new SameboySyncSettings(); _syncSettings = syncSettings ?? new();
var model = _syncSettings.ConsoleMode; var model = _syncSettings.ConsoleMode;
if (model is SameboySyncSettings.GBModel.Auto) if (model is SameboySyncSettings.GBModel.Auto)
@ -86,7 +143,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
DeterministicEmulation = true; 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(); InitMemoryDomains();
InitMemoryCallbacks(); InitMemoryCallbacks();
@ -111,14 +168,6 @@ namespace BizHawk.Emulation.Cores.Nintendo.Sameboy
PutSettings(_settings); 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); LibSameboy.sameboy_setrtcdivisoroffset(SameboyState, _syncSettings.RTCDivisorOffset);
CycleCount = 0; 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)); biz_t* biz = calloc(1, sizeof (biz_t));
GB_random_seed(0); GB_random_seed(0);
GB_init(&biz->gb, model); GB_init(&biz->gb, model);
// 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_rom_from_buffer(&biz->gb, romdata, romlen);
}
GB_load_boot_rom_from_buffer(&biz->gb, biosdata, bioslen); 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_sample_rate(&biz->gb, GB_get_clock_rate(&biz->gb) / 2 / 8);
GB_set_rumble_mode(&biz->gb, GB_RUMBLE_ALL_GAMES); GB_set_rumble_mode(&biz->gb, GB_RUMBLE_ALL_GAMES);
@ -171,6 +175,16 @@ EXPORT void sameboy_destroy(biz_t* biz)
free(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) EXPORT void sameboy_setinputcallback(biz_t* biz, input_callback_t callback)
{ {
biz->input_cb = callback; biz->input_cb = callback;