GBS support using SameBoy
This commit is contained in:
parent
0c6f0523a0
commit
9528a2030f
Binary file not shown.
Binary file not shown.
|
@ -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);
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue