Move InputCallbackSystem from CoreComm to IInputPollable, and refactor all cores accordingly. Lua - OnInputPoll() - log to the user when attemping to add a callback of this type to a core that has not implemented input callbacks. Mark all unmanaged cores' implementations of the InputCallbackSystem as FeatureNotImpleented, won't have any effect on functionality, but will help us keep track of the fact that they still have a bit of work to do. Still todo: ActiveChanged event handler on the base implementation of IInputCallbackSystem

This commit is contained in:
adelikat 2014-12-04 00:43:12 +00:00
parent 7ffe07c44b
commit a07263c04e
37 changed files with 197 additions and 55 deletions

View File

@ -3,7 +3,8 @@ using System.Linq;
using System.ComponentModel;
using LuaInterface;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
namespace BizHawk.Client.Common
{
@ -155,7 +156,27 @@ namespace BizHawk.Client.Common
{
var nlf = new NamedLuaFunction(luaf, "OnInputPoll", LogOutputCallback, CurrentThread, name);
_luaFunctions.Add(nlf);
Global.Emulator.CoreComm.InputCallback.Add(nlf.Callback);
if (Global.Emulator.CanPollInput())
{
try
{
(Global.Emulator as IInputPollable).InputCallbacks.Add(nlf.Callback);
}
catch (NotImplementedException)
{
LogNotImplemented();
}
}
else
{
LogNotImplemented();
}
}
private void LogNotImplemented()
{
Log(string.Format("Error: {0} does not yet implement input polling callbacks"));
}
[LuaMethodAttributes(

View File

@ -1,6 +1,9 @@
using System.Collections.Generic;
using System.Linq;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
namespace BizHawk.Client.Common
{
public class LuaFunctionList : List<NamedLuaFunction>
@ -15,14 +18,22 @@ namespace BizHawk.Client.Common
public new bool Remove(NamedLuaFunction function)
{
Global.Emulator.CoreComm.InputCallback.Remove(function.Callback);
if (Global.Emulator.CanPollInput())
{
(Global.Emulator as IInputPollable).InputCallbacks.Remove(function.Callback);
}
Global.Emulator.CoreComm.MemoryCallbackSystem.Remove(function.Callback);
return base.Remove(function);
}
public void ClearAll()
{
Global.Emulator.CoreComm.InputCallback.RemoveAll(this.Select(x => x.Callback));
if (Global.Emulator.CanPollInput())
{
(Global.Emulator as IInputPollable).InputCallbacks.RemoveAll(this.Select(x => x.Callback));
}
Global.Emulator.CoreComm.MemoryCallbackSystem.RemoveAll(this.Select(x => x.Callback));
Clear();
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
namespace BizHawk.Emulation.Common
{
public class InputCallbackSystem : List<Action>, IInputCallbackSystem
{
public void Call()
{
foreach (var action in this)
{
action();
}
}
public void RemoveAll(IEnumerable<Action> actions)
{
foreach (var action in actions)
{
this.Remove(action);
}
}
}
}

View File

@ -50,6 +50,7 @@
<Link>VersionInfo.cs</Link>
</Compile>
<Compile Include="Base Implementations\ControllerDefinition.cs" />
<Compile Include="Base Implementations\InputCallbackSystem.cs" />
<Compile Include="Base Implementations\NullController.cs" />
<Compile Include="Base Implementations\NullEmulator.cs" />
<Compile Include="Base Implementations\NullSound.cs" />
@ -67,6 +68,7 @@
<Compile Include="Interfaces\ICoreService.cs" />
<Compile Include="Interfaces\IDebuggable.cs" />
<Compile Include="Interfaces\IEmulator.cs" />
<Compile Include="Interfaces\IInputCallbackSystem.cs" />
<Compile Include="Interfaces\IInputPollable.cs" />
<Compile Include="Interfaces\IMemoryDomains.cs" />
<Compile Include="Interfaces\ISaveRam.cs" />

View File

@ -14,11 +14,6 @@ namespace BizHawk.Emulation.Common
/// </summary>
public TraceBuffer Tracer = new TraceBuffer();
/// <summary>
/// for emu.on_snoop()
/// </summary>
public InputCallbackSystem InputCallback = new InputCallbackSystem();
public MemoryCallbackSystem MemoryCallbackSystem = new MemoryCallbackSystem();
public double VsyncRate
@ -121,25 +116,6 @@ namespace BizHawk.Emulation.Common
private bool logging;
}
public class InputCallbackSystem : List<Action>
{
public void Call()
{
foreach (var action in this)
{
action();
}
}
public void RemoveAll(IEnumerable<Action> actions)
{
foreach (var action in actions)
{
this.Remove(action);
}
}
}
public class MemoryCallbackSystem
{
private readonly List<Action> _reads = new List<Action>();

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
namespace BizHawk.Emulation.Common
{
// TODO: This isn't a CoreService, it is a sub class of a core service, it would be nice to make that clear
public interface IInputCallbackSystem : IList<Action>
{
/// <summary>
/// Will iterate and call every callback
/// </summary>
void Call();
/// <summary>
/// Will remove the given list of callbacks
/// </summary>
void RemoveAll(IEnumerable<Action> actions);
}
}

View File

@ -12,5 +12,7 @@
/// All cores should define it the same, a lag frame is a frame in which input was not polled.
/// </summary>
bool IsLagFrame { get; }
IInputCallbackSystem InputCallbacks { get; }
}
}

View File

@ -14,6 +14,8 @@ namespace BizHawk.Emulation.Cores.Calculators
set { _lagCount = value; }
}
public IInputCallbackSystem InputCallbacks { get; private set; }
public bool IsLagFrame
{
get { return _isLag; }

View File

@ -52,6 +52,7 @@ namespace BizHawk.Emulation.Cores.Calculators
[CoreConstructor("TI83")]
public TI83(CoreComm comm, GameInfo game, byte[] rom, object Settings)
{
InputCallbacks = new InputCallbackSystem();
PutSettings((TI83Settings)Settings ?? new TI83Settings());
CoreComm = comm;
@ -186,7 +187,7 @@ namespace BizHawk.Emulation.Cores.Calculators
private byte ReadKeyboard()
{
CoreComm.InputCallback.Call();
InputCallbacks.Call();
//ref TI-9X
int ret = 0xFF;

View File

@ -32,7 +32,7 @@
public void PollInput()
{
_c64.CoreComm.InputCallback.Call();
_c64.InputCallbacks.Call();
// scan joysticks
pollIndex = 0;
for (int j = 0; j < 5; j++)

View File

@ -186,6 +186,9 @@ namespace BizHawk.Emulation.Cores.Computers.Commodore64
public bool BinarySaveStatesPreferred { get { return false; } }
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
public IInputCallbackSystem InputCallbacks { get { return _inputCallbacks; } }
private void SetupMemoryDomains()
{
// chips must be initialized before this code runs!

View File

@ -424,7 +424,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
public byte ReadControls1(bool peek)
{
CoreComm.InputCallback.Call();
InputCallbacks.Call();
byte value = 0xFF;
if (Controller["P1 Up"]) { value &= 0xEF; }
@ -443,7 +443,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
public byte ReadControls2(bool peek)
{
CoreComm.InputCallback.Call();
InputCallbacks.Call();
byte value = 0xFF;
if (Controller["P2 Up"]) { value &= 0xEF; }

View File

@ -15,6 +15,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
get { return _islag; }
}
public IInputCallbackSystem InputCallbacks { get; private set; }
private bool _islag = true;
private int _lagcount;
}

View File

@ -24,6 +24,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
[CoreConstructor("A26")]
public Atari2600(CoreComm comm, GameInfo game, byte[] rom, object settings, object syncSettings)
{
InputCallbacks = new InputCallbackSystem();
Ram = new byte[128];
CoreComm = comm;
Settings = (A2600Settings)settings ?? new A2600Settings();
@ -137,7 +138,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari2600
// give the emu a minimal of input\output connections so it doesn't crash
var comm = new CoreComm(null, null);
comm.InputCallback = new InputCallbackSystem();
using (Atari2600 emu = new Atari2600(new CoreComm(null, null), newgame, rom, null, null))
{
emu.Controller = new NullController();

View File

@ -15,6 +15,8 @@ namespace BizHawk.Emulation.Cores.Atari.Atari7800
get { return _islag; }
}
public IInputCallbackSystem InputCallbacks { get; private set; }
private bool _islag = true;
private int _lagcount;
}

View File

@ -122,6 +122,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari7800
public Atari7800(CoreComm comm, GameInfo game, byte[] rom, string GameDBfn)
{
InputCallbacks = new InputCallbackSystem();
CoreComm = comm;
byte[] highscoreBIOS = comm.CoreFileProvider.GetFirmware("A78", "Bios_HSC", false, "Some functions may not work without the high score BIOS.");
byte[] pal_bios = comm.CoreFileProvider.GetFirmware("A78", "Bios_PAL", false, "The game will not run if the correct region BIOS is not available.");
@ -186,7 +187,7 @@ namespace BizHawk.Emulation.Cores.Atari.Atari7800
logger);
theMachine.Reset();
theMachine.InputState.InputPollCallback = CoreComm.InputCallback.Call;
theMachine.InputState.InputPollCallback = InputCallbacks.Call;
ControlAdapter = new Atari7800Control(theMachine);
ControllerDefinition = ControlAdapter.ControlType;

View File

@ -139,6 +139,14 @@ namespace BizHawk.Emulation.Cores.Atari.Lynx
public int LagCount { get; set; }
public bool IsLagFrame { get; private set; }
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
// TODO: optimize managed to unmanaged using the ActiveChanged event
public IInputCallbackSystem InputCallbacks
{
[FeatureNotImplemented]get { return _inputCallbacks; }
}
public string SystemId { get { return "Lynx"; } }
public bool DeterministicEmulation { get { return true; } }

View File

@ -60,6 +60,9 @@ namespace BizHawk.Emulation.Cores.ColecoVision
SetupMemoryDomains();
}
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
public IInputCallbackSystem InputCallbacks { get { return _inputCallbacks; } }
public MemoryDomainList MemoryDomains { get { return memoryDomains; } }
MemoryDomainList memoryDomains;
const ushort RamSizeMask = 0x03FF;

View File

@ -87,6 +87,12 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
public int Frame { get; private set; }
public int LagCount { get; set; }
public bool IsLagFrame { get; private set; }
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
// TODO: optimize managed to unmanaged using the ActiveChanged event
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { return _inputCallbacks; } }
public string SystemId { get { return "GBA"; } }
public bool DeterministicEmulation { get { return true; } }
@ -309,7 +315,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
LibMeteor.Buttons GetInput()
{
CoreComm.InputCallback.Call();
InputCallbacks.Call();
// libmeteor bitflips everything itself, so 0 == off, 1 == on
IsLagFrame = false;
LibMeteor.Buttons ret = 0;

View File

@ -109,6 +109,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
public int LagCount { get; set; }
public bool IsLagFrame { get; private set; }
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
// TODO: optimize managed to unmanaged using the ActiveChanged event
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { return _inputCallbacks; } }
public string SystemId { get { return "GBA"; } }
public bool DeterministicEmulation { get; private set; }
@ -272,7 +277,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
void InitCallbacks()
{
padcb = new LibVBANext.StandardCallback(() => CoreComm.InputCallback.Call());
padcb = new LibVBANext.StandardCallback(() => InputCallbacks.Call());
fetchcb = new LibVBANext.AddressCallback((addr) => CoreComm.MemoryCallbackSystem.CallExecute(addr));
readcb = new LibVBANext.AddressCallback((addr) => CoreComm.MemoryCallbackSystem.CallRead(addr));
writecb = new LibVBANext.AddressCallback((addr) => CoreComm.MemoryCallbackSystem.CallWrite(addr));
@ -281,7 +286,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.GBA
void SyncCallbacks()
{
LibVBANext.SetPadCallback(Core, CoreComm.InputCallback.Any() ? padcb : null);
LibVBANext.SetPadCallback(Core, InputCallbacks.Any() ? padcb : null);
LibVBANext.SetFetchCallback(Core, CoreComm.MemoryCallbackSystem.HasExecutes ? fetchcb : null);
LibVBANext.SetReadCallback(Core, CoreComm.MemoryCallbackSystem.HasReads ? readcb : null);
LibVBANext.SetWriteCallback(Core, CoreComm.MemoryCallbackSystem.HasWrites ? writecb : null);

View File

@ -36,6 +36,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
public int LagCount { get; set; }
public bool IsLagFrame { get; private set; }
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
// TODO: optimize managed to unmanaged using the ActiveChanged event
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { return _inputCallbacks; } }
// all cycle counts are relative to a 2*1024*1024 mhz refclock
/// <summary>
@ -222,7 +227,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
LibGambatte.Buttons ControllerCallback()
{
CoreComm.InputCallback.Call();
InputCallbacks.Call();
IsLagFrame = false;
return CurrentButtons;
}

View File

@ -79,10 +79,18 @@ namespace BizHawk.Emulation.Cores.Nintendo.Gameboy
SetMemoryDomains();
L.CoreComm.InputCallback = CoreComm.InputCallback;
R.CoreComm.InputCallback = CoreComm.InputCallback;
foreach (var callback in InputCallbacks)
{
L.InputCallbacks.Add(callback);
R.InputCallbacks.Add(callback);
}
}
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
// TODO: optimize managed to unmanaged using the ActiveChanged event
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { return _inputCallbacks; } }
public IVideoProvider VideoProvider { get { return this; } }
public ISoundProvider SoundProvider { get { return null; } }
public ISyncSoundProvider SyncSoundProvider { get { return this; } }

View File

@ -121,7 +121,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
// Order is important because the register with the mupen core
_videoProvider = new N64VideoProvider(api, videosettings);
_audioProvider = new N64Audio(api);
_inputProvider = new N64Input(api, comm, this._syncSettings.Controllers);
_inputProvider = new N64Input(this as IInputPollable, api, comm, this._syncSettings.Controllers);
string rsp = _syncSettings.Rsp == N64SyncSettings.RspType.Rsp_Hle ?
@ -410,6 +410,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
api.setWriteCallback(writecb);
}
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
// TODO: optimize managed to unmanaged using the ActiveChanged event
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { return _inputCallbacks; } }
#endregion
}
}

View File

@ -48,8 +48,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
}
};
public N64Input(mupen64plusApi core, CoreComm comm, N64SyncSettings.N64ControllerSettings[] controllerSettings)
private readonly IInputPollable _emuCore;
public N64Input(IInputPollable emuCore, mupen64plusApi core, CoreComm comm, N64SyncSettings.N64ControllerSettings[] controllerSettings)
{
_emuCore = emuCore;
api = new mupen64plusInputApi(core);
CoreComm = comm;
@ -81,7 +84,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.N64
/// <param name="i">Id of controller to update and shove</param>
public int GetControllerInput(int i)
{
CoreComm.InputCallback.Call();
_emuCore.InputCallbacks.Call();
ThisFrameInputPolled = true;
// Analog stick right = +X

View File

@ -420,7 +420,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
byte read_joyport(int addr)
{
CoreComm.InputCallback.Call();
InputCallbacks.Call();
lagged = false;
byte ret = addr == 0x4016 ? ControllerDeck.ReadA(Controller) : ControllerDeck.ReadB(Controller);
ret &= 0x1f;

View File

@ -322,10 +322,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.NES
public int LagCount { get { return _lagcount; } set { _lagcount = value; } }
public bool IsLagFrame { get { return islag; } }
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
public IInputCallbackSystem InputCallbacks { get { return _inputCallbacks; } }
public bool DeterministicEmulation { get { return true; } }
public byte[] CloneSaveRam()
{
if (board is FDS)

View File

@ -392,6 +392,8 @@ namespace BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES
#endregion
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { throw new NotImplementedException(); } }
#region bootgod
public RomStatus? BootGodStatus { get; private set; }

View File

@ -241,6 +241,11 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
};
}
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
// TODO: optimize managed to unmanaged using the ActiveChanged event
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { return _inputCallbacks; } }
[FeatureNotImplemented]
public void SetCpuRegister(string register, int value)
{
@ -440,7 +445,7 @@ namespace BizHawk.Emulation.Cores.Nintendo.SNES
{
// as this is implemented right now, only P1 and P2 normal controllers work
CoreComm.InputCallback.Call();
InputCallbacks.Call();
//Console.WriteLine("{0} {1} {2} {3}", port, device, index, id);
string key = "P" + (1 + port) + " ";

View File

@ -64,7 +64,7 @@ namespace BizHawk.Emulation.Cores.PCEngine
byte ReadInput()
{
CoreComm.InputCallback.Call();
InputCallbacks.Call();
byte value = 0x3F;
int player = SelectedController + 1;

View File

@ -295,6 +295,9 @@ namespace BizHawk.Emulation.Cores.PCEngine
public int LagCount { get { return lagCount; } set { lagCount = value; } }
public bool IsLagFrame { get { return isLag; } }
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
public IInputCallbackSystem InputCallbacks { get { return _inputCallbacks; } }
public void ResetCounters()
{
// this should just be a public setter instead of a new method.

View File

@ -45,6 +45,9 @@ namespace BizHawk.Emulation.Cores.Sega.Genesis
private SoundMixer SoundMixer;
[FeatureNotImplemented]
public IInputCallbackSystem InputCallbacks { get { throw new NotImplementedException(); } }
public void ResetCounters()
{
Frame = 0;

View File

@ -108,7 +108,7 @@ namespace BizHawk.Emulation.Cores.Sega.Genesis
void ReadController(ref byte data)
{
CoreComm.InputCallback.Call();
InputCallbacks.Call();
data &= 0xC0;
if ((data & 0x40) != 0) // TH high
{

View File

@ -42,7 +42,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
byte ReadControls1()
{
CoreComm.InputCallback.Call();
InputCallbacks.Call();
lagged = false;
byte value = 0xFF;
@ -61,7 +61,7 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
byte ReadControls2()
{
CoreComm.InputCallback.Call();
InputCallbacks.Call();
lagged = false;
byte value = 0xFF;

View File

@ -78,6 +78,10 @@ namespace BizHawk.Emulation.Cores.Sega.MasterSystem
public int Frame { get { return frame; } set { frame = value; } }
public int LagCount { get { return lagCount; } set { lagCount = value; } }
public bool IsLagFrame { get { return isLag; } }
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
public IInputCallbackSystem InputCallbacks { get { return _inputCallbacks; } }
byte Port01 = 0xFF;
byte Port02 = 0xFF;
byte Port3E = 0xAF;

View File

@ -74,7 +74,7 @@ namespace BizHawk.Emulation.Cores.Sega.Saturn
ActivateGL();
Init(bios);
InputCallbackH = new LibYabause.InputCallback(() => CoreComm.InputCallback.Call());
InputCallbackH = new LibYabause.InputCallback(() => InputCallbacks.Call());
LibYabause.libyabause_setinputcallback(InputCallbackH);
CoreComm.UsesDriveLed = true;
@ -292,6 +292,11 @@ namespace BizHawk.Emulation.Cores.Sega.Saturn
public int LagCount { get; set; }
public bool IsLagFrame { get; private set; }
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
// TODO: optimize managed to unmanaged using the ActiveChanged event
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { return _inputCallbacks; } }
public string SystemId { get { return "SAT"; } }
public bool DeterministicEmulation { get { return true; } }

View File

@ -375,10 +375,15 @@ namespace BizHawk.Emulation.Cores.Consoles.Sega.gpgx
// core callback for input
void input_callback()
{
CoreComm.InputCallback.Call();
InputCallbacks.Call();
IsLagFrame = false;
}
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
// TODO: optimize managed to unmanaged using the ActiveChanged event
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { return _inputCallbacks; } }
#endregion
// TODO: use render and rendersound

View File

@ -175,6 +175,10 @@ namespace BizHawk.Emulation.Cores.WonderSwan
public int LagCount { get; set; }
public bool IsLagFrame { get; private set; }
private readonly InputCallbackSystem _inputCallbacks = new InputCallbackSystem();
// TODO: optimize managed to unmanaged using the ActiveChanged event
public IInputCallbackSystem InputCallbacks { [FeatureNotImplemented]get { return _inputCallbacks; } }
public string SystemId { get { return "WSWAN"; } }
public bool DeterministicEmulation { get; private set; }
@ -351,7 +355,7 @@ namespace BizHawk.Emulation.Cores.WonderSwan
}
void ButtonCallback()
{
CoreComm.InputCallback.Call();
InputCallbacks.Call();
}
void InitDebugCallbacks()
@ -369,7 +373,7 @@ namespace BizHawk.Emulation.Cores.WonderSwan
CoreComm.MemoryCallbackSystem.HasWrites ? WriteCallbackD : null,
CoreComm.MemoryCallbackSystem.HasExecutes ? ExecCallbackD : null);
BizSwan.bizswan_setbuttoncallback(Core,
CoreComm.InputCallback.Any() ? ButtonCallbackD : null);
InputCallbacks.Any() ? ButtonCallbackD : null);
}
#endregion