Merge pull request #1419 from upthorn/master
Extend APIHawk with a lua-like system of api libraries
This commit is contained in:
commit
5b26300e50
.gitignore
BizHawk.Client.ApiHawk
BizHawk.Client.ApiHawk.csproj
Classes
Api
EmuApi.csGameInfoApi.csJoypadApi.csMemApi.csMemApiBase.csMemEventsApi.csMemorySaveStateApi.csMovieApi.csPluginBase.csSqlApi.csUserDataApi.cs
ApiInjector.csBasicApiProvider.csClientApi.csInterfaces
BizHawk.Client.Common
BizHawk.Client.EmuHawk
BizHawk.Common
BizHawk.Emulation.Common
BizHawk.slnBizware
BizHawk.Bizware.BizwareGL.OpenTK
BizHawk.Bizware.BizwareGL.SlimDX
BizHawk.Bizware.BizwareGL
libmupen64plus
|
@ -73,3 +73,4 @@ ExternalCoreProjects/Virtu/bin/*.*
|
|||
libsnes/vs2015/libsnes.VC.db
|
||||
waterbox/**/*.wbx
|
||||
waterbox/**/*.wbx.in
|
||||
/BizHawkTool_template.zip
|
||||
|
|
|
@ -37,6 +37,10 @@
|
|||
<ItemGroup>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Data.SQLite, Version=1.0.105.2, Culture=neutral, PublicKeyToken=db937bc2d44ff139, processorArchitecture=AMD64">
|
||||
<SpecificVersion>False</SpecificVersion>
|
||||
<HintPath>..\..\Users\uptho\Documents\BizHawk-2.3\dll\System.Data.SQLite.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
|
@ -48,6 +52,19 @@
|
|||
<ItemGroup>
|
||||
<Compile Include="Attributes\BizHawkExternalToolUsageAttribute.cs" />
|
||||
<Compile Include="Attributes\BizHawkExternalToolAttribute.cs" />
|
||||
<Compile Include="Classes\ApiInjector.cs" />
|
||||
<Compile Include="Classes\Api\EmuApi.cs" />
|
||||
<Compile Include="Classes\Api\GameInfoApi.cs" />
|
||||
<Compile Include="Classes\Api\MemApi.cs" />
|
||||
<Compile Include="Classes\Api\MemApiBase.cs" />
|
||||
<Compile Include="Classes\Api\PluginBase.cs" />
|
||||
<Compile Include="Classes\Api\JoypadApi.cs" />
|
||||
<Compile Include="Classes\Api\MemEventsApi.cs" />
|
||||
<Compile Include="Classes\Api\MemorySaveStateApi.cs" />
|
||||
<Compile Include="Classes\Api\MovieApi.cs" />
|
||||
<Compile Include="Classes\Api\SqlApi.cs" />
|
||||
<Compile Include="Classes\Api\UserDataApi.cs" />
|
||||
<Compile Include="Classes\BasicApiProvider.cs" />
|
||||
<Compile Include="Classes\BizHawkSystemIdToCoreSystemEnumConverter.cs" />
|
||||
<Compile Include="Classes\Events\EventArgs\BeforeQuickLoadEventArgs.cs" />
|
||||
<Compile Include="Classes\Events\EventArgs\BeforeQuickSaveEventArgs.cs" />
|
||||
|
@ -62,7 +79,25 @@
|
|||
<Compile Include="Enums\BizHawkExternalToolUsage.cs" />
|
||||
<Compile Include="Classes\ClientApi.cs" />
|
||||
<Compile Include="Classes\ExternalToolManager.cs" />
|
||||
<Compile Include="Interfaces\Api\IComm.cs" />
|
||||
<Compile Include="Interfaces\Api\IInput.cs" />
|
||||
<Compile Include="Interfaces\Api\ITool.cs" />
|
||||
<Compile Include="Interfaces\Api\ISaveState.cs" />
|
||||
<Compile Include="Interfaces\Api\IUserData.cs" />
|
||||
<Compile Include="Interfaces\Api\ISql.cs" />
|
||||
<Compile Include="Interfaces\Api\IMovie.cs" />
|
||||
<Compile Include="Interfaces\Api\IMemorySavestate.cs" />
|
||||
<Compile Include="Interfaces\Api\IMemEvents.cs" />
|
||||
<Compile Include="Interfaces\Api\IEmu.cs" />
|
||||
<Compile Include="Interfaces\Api\IExternalApi.cs" />
|
||||
<Compile Include="Interfaces\Api\IJoypad.cs" />
|
||||
<Compile Include="Interfaces\IExternalApiProvider.cs" />
|
||||
<Compile Include="Interfaces\IExternalToolForm.cs" />
|
||||
<Compile Include="Interfaces\Api\IGameInfo.cs" />
|
||||
<Compile Include="Interfaces\Api\IGui.cs" />
|
||||
<Compile Include="Interfaces\Api\IMem.cs" />
|
||||
<Compile Include="Interfaces\IPlugin.cs" />
|
||||
<Compile Include="Interfaces\Api\IApiContainer.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
|
@ -95,4 +130,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
|
@ -0,0 +1,459 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.IEmulatorExtensions;
|
||||
using BizHawk.Emulation.Cores.Nintendo.NES;
|
||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||
using BizHawk.Emulation.Cores.PCEngine;
|
||||
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
|
||||
using BizHawk.Emulation.Cores.Sega.MasterSystem;
|
||||
using BizHawk.Emulation.Cores.WonderSwan;
|
||||
using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
[Description("A library for interacting with the currently loaded emulator core")]
|
||||
public sealed class EmuApi : IEmu
|
||||
{
|
||||
private static class EmuStatic
|
||||
{
|
||||
public static void DisplayVsync(bool enabled)
|
||||
{
|
||||
Global.Config.VSync = enabled;
|
||||
}
|
||||
public static string GetSystemId()
|
||||
{
|
||||
return Global.Game.System;
|
||||
}
|
||||
public static void LimitFramerate(bool enabled)
|
||||
{
|
||||
Global.Config.ClockThrottle = enabled;
|
||||
}
|
||||
|
||||
public static void MinimizeFrameskip(bool enabled)
|
||||
{
|
||||
Global.Config.AutoMinimizeSkipping = enabled;
|
||||
}
|
||||
|
||||
}
|
||||
[RequiredService]
|
||||
private IEmulator Emulator { get; set; }
|
||||
|
||||
[OptionalService]
|
||||
private IDebuggable DebuggableCore { get; set; }
|
||||
|
||||
[OptionalService]
|
||||
private IDisassemblable DisassemblableCore { get; set; }
|
||||
|
||||
[OptionalService]
|
||||
private IMemoryDomains MemoryDomains { get; set; }
|
||||
|
||||
[OptionalService]
|
||||
private IInputPollable InputPollableCore { get; set; }
|
||||
|
||||
[OptionalService]
|
||||
private IRegionable RegionableCore { get; set; }
|
||||
|
||||
[OptionalService]
|
||||
private IBoardInfo BoardInfo { get; set; }
|
||||
|
||||
public Action FrameAdvanceCallback { get; set; }
|
||||
public Action YieldCallback { get; set; }
|
||||
|
||||
public EmuApi()
|
||||
{ }
|
||||
|
||||
public void DisplayVsync(bool enabled)
|
||||
{
|
||||
EmuStatic.DisplayVsync(enabled);
|
||||
}
|
||||
|
||||
public void FrameAdvance()
|
||||
{
|
||||
FrameAdvanceCallback();
|
||||
}
|
||||
|
||||
public int FrameCount()
|
||||
{
|
||||
return Emulator.Frame;
|
||||
}
|
||||
|
||||
public object Disassemble(uint pc, string name = "")
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DisassemblableCore == null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
MemoryDomain domain = MemoryDomains.SystemBus;
|
||||
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
domain = MemoryDomains[name];
|
||||
}
|
||||
|
||||
int l;
|
||||
var d = DisassemblableCore.Disassemble(domain, pc, out l);
|
||||
return new { disasm = d, length = l };
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
Console.WriteLine($"Error: {Emulator.Attributes().CoreName} does not yet implement disassemble()");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ulong? GetRegister(string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DebuggableCore == null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
var registers = DebuggableCore.GetCpuFlagsAndRegisters();
|
||||
ulong? value = null;
|
||||
if (registers.ContainsKey(name)) value = registers[name].Value;
|
||||
return value;
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
Console.WriteLine($"Error: {Emulator.Attributes().CoreName} does not yet implement getregister()");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, ulong> GetRegisters()
|
||||
{
|
||||
var table = new Dictionary<string, ulong>();
|
||||
|
||||
try
|
||||
{
|
||||
if (DebuggableCore == null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
foreach (var kvp in DebuggableCore.GetCpuFlagsAndRegisters())
|
||||
{
|
||||
table[kvp.Key] = kvp.Value.Value;
|
||||
}
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
Console.WriteLine($"Error: {Emulator.Attributes().CoreName} does not yet implement getregisters()");
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
public void SetRegister(string register, int value)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DebuggableCore == null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
DebuggableCore.SetCpuRegister(register, value);
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
Console.WriteLine($"Error: {Emulator.Attributes().CoreName} does not yet implement setregister()");
|
||||
}
|
||||
}
|
||||
|
||||
public long TotalExecutedycles()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DebuggableCore == null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
return DebuggableCore.TotalExecutedCycles;
|
||||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
Console.WriteLine($"Error: {Emulator.Attributes().CoreName} does not yet implement totalexecutedcycles()");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public string GetSystemId()
|
||||
{
|
||||
return EmuStatic.GetSystemId();
|
||||
}
|
||||
|
||||
public bool IsLagged()
|
||||
{
|
||||
if (InputPollableCore != null)
|
||||
{
|
||||
return InputPollableCore.IsLagFrame;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Can not get lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable");
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SetIsLagged(bool value = true)
|
||||
{
|
||||
if (InputPollableCore != null)
|
||||
{
|
||||
InputPollableCore.IsLagFrame = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Can not set lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable");
|
||||
}
|
||||
}
|
||||
|
||||
public int LagCount()
|
||||
{
|
||||
if (InputPollableCore != null)
|
||||
{
|
||||
return InputPollableCore.LagCount;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Can not get lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable");
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void SetLagCount(int count)
|
||||
{
|
||||
if (InputPollableCore != null)
|
||||
{
|
||||
InputPollableCore.LagCount = count;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Can not set lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable");
|
||||
}
|
||||
}
|
||||
|
||||
public void LimitFramerate(bool enabled)
|
||||
{
|
||||
EmuStatic.LimitFramerate(enabled);
|
||||
}
|
||||
|
||||
public void MinimizeFrameskip(bool enabled)
|
||||
{
|
||||
EmuStatic.MinimizeFrameskip(enabled);
|
||||
}
|
||||
|
||||
public void Yield()
|
||||
{
|
||||
YieldCallback();
|
||||
}
|
||||
|
||||
public string GetDisplayType()
|
||||
{
|
||||
if (RegionableCore != null)
|
||||
{
|
||||
return RegionableCore.Region.ToString();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public string GetBoardName()
|
||||
{
|
||||
if (BoardInfo != null)
|
||||
{
|
||||
return BoardInfo.BoardName;
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
public object GetSettings()
|
||||
{
|
||||
if (Emulator is GPGX)
|
||||
{
|
||||
var gpgx = Emulator as GPGX;
|
||||
return gpgx.GetSettings();
|
||||
}
|
||||
else if (Emulator is LibsnesCore)
|
||||
{
|
||||
var snes = Emulator as LibsnesCore;
|
||||
return snes.GetSettings();
|
||||
}
|
||||
else if (Emulator is NES)
|
||||
{
|
||||
var nes = Emulator as NES;
|
||||
return nes.GetSettings();
|
||||
}
|
||||
else if (Emulator is QuickNES)
|
||||
{
|
||||
var quicknes = Emulator as QuickNES;
|
||||
return quicknes.GetSettings();
|
||||
}
|
||||
else if (Emulator is PCEngine)
|
||||
{
|
||||
var pce = Emulator as PCEngine;
|
||||
return pce.GetSettings();
|
||||
}
|
||||
else if (Emulator is SMS)
|
||||
{
|
||||
var sms = Emulator as SMS;
|
||||
return sms.GetSettings();
|
||||
}
|
||||
else if (Emulator is WonderSwan)
|
||||
{
|
||||
var ws = Emulator as WonderSwan;
|
||||
return ws.GetSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public bool PutSettings(object settings)
|
||||
{
|
||||
if (Emulator is GPGX)
|
||||
{
|
||||
var gpgx = Emulator as GPGX;
|
||||
return gpgx.PutSettings(settings as GPGX.GPGXSettings);
|
||||
}
|
||||
else if (Emulator is LibsnesCore)
|
||||
{
|
||||
var snes = Emulator as LibsnesCore;
|
||||
return snes.PutSettings(settings as LibsnesCore.SnesSettings);
|
||||
}
|
||||
else if (Emulator is NES)
|
||||
{
|
||||
var nes = Emulator as NES;
|
||||
return nes.PutSettings(settings as NES.NESSettings);
|
||||
}
|
||||
else if (Emulator is QuickNES)
|
||||
{
|
||||
var quicknes = Emulator as QuickNES;
|
||||
return quicknes.PutSettings(settings as QuickNES.QuickNESSettings);
|
||||
}
|
||||
else if (Emulator is PCEngine)
|
||||
{
|
||||
var pce = Emulator as PCEngine;
|
||||
return pce.PutSettings(settings as PCEngine.PCESettings);
|
||||
}
|
||||
else if (Emulator is SMS)
|
||||
{
|
||||
var sms = Emulator as SMS;
|
||||
return sms.PutSettings(settings as SMS.SMSSettings);
|
||||
}
|
||||
else if (Emulator is WonderSwan)
|
||||
{
|
||||
var ws = Emulator as WonderSwan;
|
||||
return ws.PutSettings(settings as WonderSwan.Settings);
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public void SetRenderPlanes(params bool[] luaParam)
|
||||
{
|
||||
if (Emulator is GPGX)
|
||||
{
|
||||
var gpgx = Emulator as GPGX;
|
||||
var s = gpgx.GetSettings();
|
||||
s.DrawBGA = luaParam[0];
|
||||
s.DrawBGB = luaParam[1];
|
||||
s.DrawBGW = luaParam[2];
|
||||
s.DrawObj = luaParam[3];
|
||||
gpgx.PutSettings(s);
|
||||
|
||||
}
|
||||
else if (Emulator is LibsnesCore)
|
||||
{
|
||||
var snes = Emulator as LibsnesCore;
|
||||
var s = snes.GetSettings();
|
||||
s.ShowBG1_0 = s.ShowBG1_1 = luaParam[0];
|
||||
s.ShowBG2_0 = s.ShowBG2_1 = luaParam[1];
|
||||
s.ShowBG3_0 = s.ShowBG3_1 = luaParam[2];
|
||||
s.ShowBG4_0 = s.ShowBG4_1 = luaParam[3];
|
||||
s.ShowOBJ_0 = luaParam[4];
|
||||
s.ShowOBJ_1 = luaParam[5];
|
||||
s.ShowOBJ_2 = luaParam[6];
|
||||
s.ShowOBJ_3 = luaParam[7];
|
||||
snes.PutSettings(s);
|
||||
}
|
||||
else if (Emulator is NES)
|
||||
{
|
||||
// in the future, we could do something more arbitrary here.
|
||||
// but this isn't any worse than the old system
|
||||
var nes = Emulator as NES;
|
||||
var s = nes.GetSettings();
|
||||
s.DispSprites = luaParam[0];
|
||||
s.DispBackground = luaParam[1];
|
||||
nes.PutSettings(s);
|
||||
}
|
||||
else if (Emulator is QuickNES)
|
||||
{
|
||||
var quicknes = Emulator as QuickNES;
|
||||
var s = quicknes.GetSettings();
|
||||
|
||||
// this core doesn't support disabling BG
|
||||
bool showsp = GetSetting(0, luaParam);
|
||||
if (showsp && s.NumSprites == 0)
|
||||
{
|
||||
s.NumSprites = 8;
|
||||
}
|
||||
else if (!showsp && s.NumSprites > 0)
|
||||
{
|
||||
s.NumSprites = 0;
|
||||
}
|
||||
|
||||
quicknes.PutSettings(s);
|
||||
}
|
||||
else if (Emulator is PCEngine)
|
||||
{
|
||||
var pce = Emulator as PCEngine;
|
||||
var s = pce.GetSettings();
|
||||
s.ShowOBJ1 = GetSetting(0, luaParam);
|
||||
s.ShowBG1 = GetSetting(1, luaParam);
|
||||
if (luaParam.Length > 2)
|
||||
{
|
||||
s.ShowOBJ2 = GetSetting(2, luaParam);
|
||||
s.ShowBG2 = GetSetting(3, luaParam);
|
||||
}
|
||||
|
||||
pce.PutSettings(s);
|
||||
}
|
||||
else if (Emulator is SMS)
|
||||
{
|
||||
var sms = Emulator as SMS;
|
||||
var s = sms.GetSettings();
|
||||
s.DispOBJ = GetSetting(0, luaParam);
|
||||
s.DispBG = GetSetting(1, luaParam);
|
||||
sms.PutSettings(s);
|
||||
}
|
||||
else if (Emulator is WonderSwan)
|
||||
{
|
||||
var ws = Emulator as WonderSwan;
|
||||
var s = ws.GetSettings();
|
||||
s.EnableSprites = GetSetting(0, luaParam);
|
||||
s.EnableFG = GetSetting(1, luaParam);
|
||||
s.EnableBG = GetSetting(2, luaParam);
|
||||
ws.PutSettings(s);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool GetSetting(int index, bool[] settings)
|
||||
{
|
||||
if (index < settings.Length)
|
||||
{
|
||||
return settings[index];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public sealed class GameInfoApi : IGameInfo
|
||||
{
|
||||
[OptionalService]
|
||||
private IBoardInfo BoardInfo { get; set; }
|
||||
|
||||
public GameInfoApi()
|
||||
{ }
|
||||
|
||||
public string GetRomName()
|
||||
{
|
||||
if (Global.Game != null)
|
||||
{
|
||||
return Global.Game.Name ?? "";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public string GetRomHash()
|
||||
{
|
||||
if (Global.Game != null)
|
||||
{
|
||||
return Global.Game.Hash ?? "";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public bool InDatabase()
|
||||
{
|
||||
if (Global.Game != null)
|
||||
{
|
||||
return !Global.Game.NotInDatabase;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public string GetStatus()
|
||||
{
|
||||
if (Global.Game != null)
|
||||
{
|
||||
return Global.Game.Status.ToString();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public bool IsStatusBad()
|
||||
{
|
||||
if (Global.Game != null)
|
||||
{
|
||||
return Global.Game.IsRomStatusBad();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public string GetBoardType()
|
||||
{
|
||||
return BoardInfo?.BoardName ?? "";
|
||||
}
|
||||
|
||||
public Dictionary<string, string> GetOptions()
|
||||
{
|
||||
var options = new Dictionary<string, string>();
|
||||
|
||||
if (Global.Game != null)
|
||||
{
|
||||
foreach (var option in Global.Game.GetOptionsDict())
|
||||
{
|
||||
options[option.Key] = option.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return options;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,222 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Client.Common;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public sealed class JoypadApi : IJoypad
|
||||
{
|
||||
public JoypadApi()
|
||||
{ }
|
||||
|
||||
public Dictionary<string,dynamic> Get(int? controller = null)
|
||||
{
|
||||
var buttons = new Dictionary<string, dynamic>();
|
||||
var adaptor = Global.AutofireStickyXORAdapter;
|
||||
foreach (var button in adaptor.Source.Definition.BoolButtons)
|
||||
{
|
||||
if (!controller.HasValue)
|
||||
{
|
||||
buttons[button] = adaptor.IsPressed(button);
|
||||
}
|
||||
else if (button.Length >= 3 && button.Substring(0, 2) == "P" + controller)
|
||||
{
|
||||
buttons[button.Substring(3)] = adaptor.IsPressed("P" + controller + " " + button.Substring(3));
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var button in adaptor.Source.Definition.FloatControls)
|
||||
{
|
||||
if (controller == null)
|
||||
{
|
||||
buttons[button] = adaptor.GetFloat(button);
|
||||
}
|
||||
else if (button.Length >= 3 && button.Substring(0, 2) == "P" + controller)
|
||||
{
|
||||
buttons[button.Substring(3)] = adaptor.GetFloat("P" + controller + " " + button.Substring(3));
|
||||
}
|
||||
}
|
||||
|
||||
buttons["clear"] = null;
|
||||
buttons["getluafunctionslist"] = null;
|
||||
buttons["output"] = null;
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
// TODO: what about float controls?
|
||||
public Dictionary<string, dynamic> GetImmediate()
|
||||
{
|
||||
var buttons = new Dictionary<string, dynamic>();
|
||||
var adaptor = Global.ActiveController;
|
||||
foreach (var button in adaptor.Definition.BoolButtons)
|
||||
{
|
||||
buttons[button] = adaptor.IsPressed(button);
|
||||
}
|
||||
foreach (var button in adaptor.Definition.FloatControls)
|
||||
{
|
||||
buttons[button] = adaptor.GetFloat(button);
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
public void SetFromMnemonicStr(string inputLogEntry)
|
||||
{
|
||||
try
|
||||
{
|
||||
var lg = Global.MovieSession.MovieControllerInstance();
|
||||
lg.SetControllersAsMnemonic(inputLogEntry);
|
||||
|
||||
foreach (var button in lg.Definition.BoolButtons)
|
||||
{
|
||||
Global.LuaAndAdaptor.SetButton(button, lg.IsPressed(button));
|
||||
}
|
||||
|
||||
foreach (var floatButton in lg.Definition.FloatControls)
|
||||
{
|
||||
Global.LuaAndAdaptor.SetFloat(floatButton, lg.GetFloat(floatButton));
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Console.WriteLine("invalid mnemonic string: " + inputLogEntry);
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(Dictionary<string,bool> buttons, int? controller = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var button in buttons.Keys)
|
||||
{
|
||||
var invert = false;
|
||||
bool? theValue;
|
||||
var theValueStr = buttons[button].ToString();
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(theValueStr))
|
||||
{
|
||||
if (theValueStr.ToLower() == "false")
|
||||
{
|
||||
theValue = false;
|
||||
}
|
||||
else if (theValueStr.ToLower() == "true")
|
||||
{
|
||||
theValue = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
invert = true;
|
||||
theValue = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
theValue = null;
|
||||
}
|
||||
|
||||
var toPress = button.ToString();
|
||||
if (controller.HasValue)
|
||||
{
|
||||
toPress = "P" + controller + " " + button;
|
||||
}
|
||||
|
||||
if (!invert)
|
||||
{
|
||||
if (theValue.HasValue) // Force
|
||||
{
|
||||
Global.LuaAndAdaptor.SetButton(toPress, theValue.Value);
|
||||
Global.ActiveController.Overrides(Global.LuaAndAdaptor);
|
||||
}
|
||||
else // Unset
|
||||
{
|
||||
Global.LuaAndAdaptor.UnSet(toPress);
|
||||
Global.ActiveController.Overrides(Global.LuaAndAdaptor);
|
||||
}
|
||||
}
|
||||
else // Inverse
|
||||
{
|
||||
Global.LuaAndAdaptor.SetInverse(toPress);
|
||||
Global.ActiveController.Overrides(Global.LuaAndAdaptor);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
/*Eat it*/
|
||||
}
|
||||
}
|
||||
public void Set(string button, bool? state = null, int? controller = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
var toPress = button;
|
||||
if (controller.HasValue)
|
||||
{
|
||||
toPress = "P" + controller + " " + button;
|
||||
}
|
||||
if (state.HasValue)
|
||||
Global.LuaAndAdaptor.SetButton(toPress, state.Value);
|
||||
else
|
||||
Global.LuaAndAdaptor.UnSet(toPress);
|
||||
Global.ActiveController.Overrides(Global.LuaAndAdaptor);
|
||||
}
|
||||
catch
|
||||
{
|
||||
/*Eat it*/
|
||||
}
|
||||
}
|
||||
public void SetAnalog(Dictionary<string,float> controls, object controller = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (var name in controls.Keys)
|
||||
{
|
||||
var theValueStr = controls[name].ToString();
|
||||
float? theValue = null;
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(theValueStr))
|
||||
{
|
||||
float f;
|
||||
if (float.TryParse(theValueStr, out f))
|
||||
{
|
||||
theValue = f;
|
||||
}
|
||||
}
|
||||
|
||||
if (controller == null)
|
||||
{
|
||||
Global.StickyXORAdapter.SetFloat(name.ToString(), theValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.StickyXORAdapter.SetFloat("P" + controller + " " + name, theValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
/*Eat it*/
|
||||
}
|
||||
}
|
||||
public void SetAnalog(string control, float? value = null, object controller = null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (controller == null)
|
||||
{
|
||||
Global.StickyXORAdapter.SetFloat(control, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
Global.StickyXORAdapter.SetFloat("P" + controller + " " + control, value);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
/*Eat it*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,288 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.IEmulatorExtensions;
|
||||
using BizHawk.Common.BufferExtensions;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public sealed class MemApi : MemApiBase, IMem
|
||||
{
|
||||
private MemoryDomain _currentMemoryDomain;
|
||||
private bool _isBigEndian = false;
|
||||
public MemApi()
|
||||
: base()
|
||||
{
|
||||
}
|
||||
|
||||
protected override MemoryDomain Domain
|
||||
{
|
||||
get
|
||||
{
|
||||
if (MemoryDomainCore != null)
|
||||
{
|
||||
if (_currentMemoryDomain == null)
|
||||
{
|
||||
_currentMemoryDomain = MemoryDomainCore.HasSystemBus
|
||||
? MemoryDomainCore.SystemBus
|
||||
: MemoryDomainCore.MainMemory;
|
||||
}
|
||||
|
||||
return _currentMemoryDomain;
|
||||
}
|
||||
|
||||
var error = $"Error: {Emulator.Attributes().CoreName} does not implement memory domains";
|
||||
Console.WriteLine(error);
|
||||
throw new NotImplementedException(error);
|
||||
}
|
||||
}
|
||||
|
||||
#region Unique Library Methods
|
||||
|
||||
public void SetBigEndian(bool enabled = true)
|
||||
{
|
||||
_isBigEndian = enabled;
|
||||
}
|
||||
|
||||
public List<string> GetMemoryDomainList()
|
||||
{
|
||||
var list = new List<string>();
|
||||
|
||||
foreach (var domain in DomainList)
|
||||
{
|
||||
list.Add(domain.Name);
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public uint GetMemoryDomainSize(string name = "")
|
||||
{
|
||||
if (string.IsNullOrEmpty(name))
|
||||
{
|
||||
return (uint)Domain.Size;
|
||||
}
|
||||
|
||||
return (uint)DomainList[VerifyMemoryDomain(name)].Size;
|
||||
}
|
||||
|
||||
public string GetCurrentMemoryDomain()
|
||||
{
|
||||
return Domain.Name;
|
||||
}
|
||||
|
||||
public uint GetCurrentMemoryDomainSize()
|
||||
{
|
||||
return (uint)Domain.Size;
|
||||
}
|
||||
|
||||
public bool UseMemoryDomain(string domain)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DomainList[domain] != null)
|
||||
{
|
||||
_currentMemoryDomain = DomainList[domain];
|
||||
return true;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Unable to find domain: {domain}");
|
||||
return false;
|
||||
}
|
||||
catch // Just in case
|
||||
{
|
||||
Console.WriteLine($"Unable to find domain: {domain}");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public string HashRegion(long addr, int count, string domain = null)
|
||||
{
|
||||
var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)];
|
||||
|
||||
// checks
|
||||
if (addr < 0 || addr >= d.Size)
|
||||
{
|
||||
string error = $"Address {addr} is outside the bounds of domain {d.Name}";
|
||||
Console.WriteLine(error);
|
||||
throw new ArgumentOutOfRangeException(error);
|
||||
}
|
||||
if (addr + count > d.Size)
|
||||
{
|
||||
string error = $"Address {addr} + count {count} is outside the bounds of domain {d.Name}";
|
||||
Console.WriteLine(error);
|
||||
throw new ArgumentOutOfRangeException(error);
|
||||
}
|
||||
|
||||
byte[] data = new byte[count];
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
data[i] = d.PeekByte(addr + i);
|
||||
}
|
||||
|
||||
using (var hasher = System.Security.Cryptography.SHA256.Create())
|
||||
{
|
||||
return hasher.ComputeHash(data).BytesToHexString();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Endian Handling
|
||||
|
||||
private int ReadSigned(long addr, int size, string domain = null)
|
||||
{
|
||||
if (_isBigEndian) return ReadSignedBig(addr, size, domain);
|
||||
else return ReadSignedLittle(addr, size, domain);
|
||||
}
|
||||
|
||||
private uint ReadUnsigned(long addr, int size, string domain = null)
|
||||
{
|
||||
if (_isBigEndian) return ReadUnsignedBig(addr, size, domain);
|
||||
else return ReadUnsignedLittle(addr, size, domain);
|
||||
}
|
||||
|
||||
private void WriteSigned(long addr, int value, int size, string domain = null)
|
||||
{
|
||||
if (_isBigEndian) WriteSignedBig(addr, value, size, domain);
|
||||
else WriteSignedLittle(addr, value, size, domain);
|
||||
}
|
||||
|
||||
private void WriteUnsigned(long addr, uint value, int size, string domain = null)
|
||||
{
|
||||
if (_isBigEndian) WriteUnsignedBig(addr, value, size, domain);
|
||||
else WriteUnsignedLittle(addr, value, size, domain);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Common Special and Legacy Methods
|
||||
|
||||
public uint ReadByte(long addr, string domain = null)
|
||||
{
|
||||
return ReadUnsignedByte(addr, domain);
|
||||
}
|
||||
|
||||
public void WriteByte(long addr, uint value, string domain = null)
|
||||
{
|
||||
WriteUnsignedByte(addr, value, domain);
|
||||
}
|
||||
|
||||
public new List<byte> ReadByteRange(long addr, int length, string domain = null)
|
||||
{
|
||||
return base.ReadByteRange(addr, length, domain);
|
||||
}
|
||||
|
||||
public new void WriteByteRange(long addr, List<byte> memoryblock, string domain = null)
|
||||
{
|
||||
base.WriteByteRange(addr, memoryblock, domain);
|
||||
}
|
||||
|
||||
public float ReadFloat(long addr, string domain = null)
|
||||
{
|
||||
return base.ReadFloat(addr, _isBigEndian, domain);
|
||||
}
|
||||
|
||||
public void WriteFloat(long addr, double value, string domain = null)
|
||||
{
|
||||
base.WriteFloat(addr, value, _isBigEndian, domain);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 1 Byte
|
||||
|
||||
public int ReadS8(long addr, string domain = null)
|
||||
{
|
||||
return (sbyte)ReadUnsignedByte(addr, domain);
|
||||
}
|
||||
|
||||
public uint ReadU8(long addr, string domain = null)
|
||||
{
|
||||
return (byte)ReadUnsignedByte(addr, domain);
|
||||
}
|
||||
|
||||
public void WriteS8(long addr, int value, string domain = null)
|
||||
{
|
||||
WriteSigned(addr, value, 1, domain);
|
||||
}
|
||||
|
||||
public void WriteU8(long addr, uint value, string domain = null)
|
||||
{
|
||||
WriteUnsignedByte(addr, value, domain);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 2 Byte
|
||||
public int ReadS16(long addr, string domain = null)
|
||||
{
|
||||
return (short)ReadSigned(addr, 2, domain);
|
||||
}
|
||||
|
||||
public void WriteS16(long addr, int value, string domain = null)
|
||||
{
|
||||
WriteSigned(addr, value, 2, domain);
|
||||
}
|
||||
|
||||
public uint ReadU16(long addr, string domain = null)
|
||||
{
|
||||
return (ushort)ReadUnsigned(addr, 2, domain);
|
||||
}
|
||||
|
||||
public void WriteU16(long addr, uint value, string domain = null)
|
||||
{
|
||||
WriteUnsigned(addr, value, 2, domain);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region 3 Byte
|
||||
|
||||
public int ReadS24(long addr, string domain = null)
|
||||
{
|
||||
return ReadSigned(addr, 3, domain);
|
||||
}
|
||||
public void WriteS24(long addr, int value, string domain = null)
|
||||
{
|
||||
WriteSigned(addr, value, 3, domain);
|
||||
}
|
||||
|
||||
public uint ReadU24(long addr, string domain = null)
|
||||
{
|
||||
return ReadUnsigned(addr, 3, domain);
|
||||
}
|
||||
|
||||
public void WriteU24(long addr, uint value, string domain = null)
|
||||
{
|
||||
WriteUnsigned(addr, value, 3, domain);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 4 Byte
|
||||
|
||||
public int ReadS32(long addr, string domain = null)
|
||||
{
|
||||
return ReadSigned(addr, 4, domain);
|
||||
}
|
||||
|
||||
public void WriteS32(long addr, int value, string domain = null)
|
||||
{
|
||||
WriteSigned(addr, value, 4, domain);
|
||||
}
|
||||
|
||||
public uint ReadU32(long addr, string domain = null)
|
||||
{
|
||||
return ReadUnsigned(addr, 4, domain);
|
||||
}
|
||||
|
||||
public void WriteU32(long addr, uint value, string domain = null)
|
||||
{
|
||||
WriteUnsigned(addr, value, 4, domain);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.IEmulatorExtensions;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
/// <summary>
|
||||
/// Base class for the Memory and MainMemory plugin libraries
|
||||
/// </summary>
|
||||
public abstract class MemApiBase : IExternalApi
|
||||
{
|
||||
[RequiredService]
|
||||
protected IEmulator Emulator { get; set; }
|
||||
|
||||
[OptionalService]
|
||||
protected IMemoryDomains MemoryDomainCore { get; set; }
|
||||
|
||||
protected abstract MemoryDomain Domain { get; }
|
||||
|
||||
protected MemApiBase()
|
||||
{ }
|
||||
|
||||
protected IMemoryDomains DomainList
|
||||
{
|
||||
get
|
||||
{
|
||||
if (MemoryDomainCore != null)
|
||||
{
|
||||
return MemoryDomainCore;
|
||||
}
|
||||
|
||||
var error = $"Error: {Emulator.Attributes().CoreName} does not implement memory domains";
|
||||
Console.WriteLine(error);
|
||||
throw new NotImplementedException(error);
|
||||
}
|
||||
}
|
||||
|
||||
public string VerifyMemoryDomain(string domain)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (DomainList[domain] == null)
|
||||
{
|
||||
Console.WriteLine($"Unable to find domain: {domain}, falling back to current");
|
||||
return Domain.Name;
|
||||
}
|
||||
|
||||
return domain;
|
||||
}
|
||||
catch // Just in case
|
||||
{
|
||||
Console.WriteLine($"Unable to find domain: {domain}, falling back to current");
|
||||
}
|
||||
|
||||
return Domain.Name;
|
||||
}
|
||||
|
||||
protected uint ReadUnsignedByte(long addr, string domain = null)
|
||||
{
|
||||
var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)];
|
||||
if (addr < d.Size)
|
||||
{
|
||||
return d.PeekByte(addr);
|
||||
}
|
||||
|
||||
Console.WriteLine("Warning: attempted read of " + addr + " outside the memory size of " + d.Size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected void WriteUnsignedByte(long addr, uint v, string domain = null)
|
||||
{
|
||||
var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)];
|
||||
if (d.CanPoke())
|
||||
{
|
||||
if (addr < d.Size)
|
||||
{
|
||||
d.PokeByte(addr, (byte)v);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Warning: attempted write to " + addr + " outside the memory size of " + d.Size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Error: the domain {d.Name} is not writable");
|
||||
}
|
||||
}
|
||||
|
||||
protected static int U2S(uint u, int size)
|
||||
{
|
||||
var s = (int)u;
|
||||
s <<= 8 * (4 - size);
|
||||
s >>= 8 * (4 - size);
|
||||
return s;
|
||||
}
|
||||
|
||||
protected int ReadSignedLittle(long addr, int size, string domain = null)
|
||||
{
|
||||
return U2S(ReadUnsignedLittle(addr, size, domain), size);
|
||||
}
|
||||
|
||||
protected uint ReadUnsignedLittle(long addr, int size, string domain = null)
|
||||
{
|
||||
uint v = 0;
|
||||
for (var i = 0; i < size; ++i)
|
||||
{
|
||||
v |= ReadUnsignedByte(addr + i, domain) << (8 * i);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
protected int ReadSignedBig(long addr, int size, string domain = null)
|
||||
{
|
||||
return U2S(ReadUnsignedBig(addr, size, domain), size);
|
||||
}
|
||||
|
||||
protected uint ReadUnsignedBig(long addr, int size, string domain = null)
|
||||
{
|
||||
uint v = 0;
|
||||
for (var i = 0; i < size; ++i)
|
||||
{
|
||||
v |= ReadUnsignedByte(addr + i, domain) << (8 * (size - 1 - i));
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
protected void WriteSignedLittle(long addr, int v, int size, string domain = null)
|
||||
{
|
||||
WriteUnsignedLittle(addr, (uint)v, size, domain);
|
||||
}
|
||||
|
||||
protected void WriteUnsignedLittle(long addr, uint v, int size, string domain = null)
|
||||
{
|
||||
for (var i = 0; i < size; ++i)
|
||||
{
|
||||
WriteUnsignedByte(addr + i, (v >> (8 * i)) & 0xFF, domain);
|
||||
}
|
||||
}
|
||||
|
||||
protected void WriteSignedBig(long addr, int v, int size, string domain = null)
|
||||
{
|
||||
WriteUnsignedBig(addr, (uint)v, size, domain);
|
||||
}
|
||||
|
||||
protected void WriteUnsignedBig(long addr, uint v, int size, string domain = null)
|
||||
{
|
||||
for (var i = 0; i < size; ++i)
|
||||
{
|
||||
WriteUnsignedByte(addr + i, (v >> (8 * (size - 1 - i))) & 0xFF, domain);
|
||||
}
|
||||
}
|
||||
|
||||
#region public Library implementations
|
||||
|
||||
protected List<byte> ReadByteRange(long addr, int length, string domain = null)
|
||||
{
|
||||
var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)];
|
||||
var lastAddr = length + addr;
|
||||
var list = new List<byte>();
|
||||
for (; addr <= lastAddr; addr++)
|
||||
{
|
||||
if (addr < d.Size)
|
||||
list.Add(d.PeekByte(addr));
|
||||
else {
|
||||
Console.WriteLine("Warning: Attempted read " + addr + " outside memory domain size of " + d.Size + " in readbyterange()");
|
||||
list.Add(0);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
protected void WriteByteRange(long addr, List<byte> memoryblock, string domain = null)
|
||||
{
|
||||
var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)];
|
||||
if (d.CanPoke())
|
||||
{
|
||||
for (var i = 0; i < memoryblock.Count; i++)
|
||||
{
|
||||
if (addr < d.Size)
|
||||
{
|
||||
d.PokeByte(addr++, memoryblock[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Warning: Attempted write " + addr + " outside memory domain size of " + d.Size + " in writebyterange()");
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Error: the domain {d.Name} is not writable");
|
||||
}
|
||||
}
|
||||
|
||||
protected float ReadFloat(long addr, bool bigendian, string domain = null)
|
||||
{
|
||||
var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)];
|
||||
if (addr < d.Size)
|
||||
{
|
||||
var val = d.PeekUint(addr, bigendian);
|
||||
var bytes = BitConverter.GetBytes(val);
|
||||
return BitConverter.ToSingle(bytes, 0);
|
||||
}
|
||||
|
||||
Console.WriteLine("Warning: Attempted read " + addr + " outside memory size of " + d.Size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected void WriteFloat(long addr, double value, bool bigendian, string domain = null)
|
||||
{
|
||||
var d = string.IsNullOrEmpty(domain) ? Domain : DomainList[VerifyMemoryDomain(domain)];
|
||||
if (d.CanPoke())
|
||||
{
|
||||
if (addr < d.Size)
|
||||
{
|
||||
var dv = (float)value;
|
||||
var bytes = BitConverter.GetBytes(dv);
|
||||
var v = BitConverter.ToUInt32(bytes, 0);
|
||||
d.PokeUint(addr, v, bigendian);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Warning: Attempted write " + addr + " outside memory size of " + d.Size);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine($"Error: the domain {Domain.Name} is not writable");
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
using System;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Common.IEmulatorExtensions;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public sealed class MemEventsApi : IMemEvents
|
||||
{
|
||||
[RequiredService]
|
||||
private IDebuggable DebuggableCore { get; set; }
|
||||
|
||||
public MemEventsApi () : base()
|
||||
{ }
|
||||
|
||||
public void AddReadCallback(Action cb, uint address, string domain)
|
||||
{
|
||||
if (DebuggableCore.MemoryCallbacksAvailable())
|
||||
{
|
||||
DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Read, "Plugin Hook", cb, address, null));
|
||||
}
|
||||
}
|
||||
public void AddWriteCallback(Action cb, uint address, string domain)
|
||||
{
|
||||
if (DebuggableCore.MemoryCallbacksAvailable())
|
||||
{
|
||||
DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Write, "Plugin Hook", cb, address, null));
|
||||
}
|
||||
}
|
||||
public void AddExecCallback(Action cb, uint address, string domain)
|
||||
{
|
||||
if (DebuggableCore.MemoryCallbacksAvailable() && DebuggableCore.MemoryCallbacks.ExecuteCallbacksAvailable)
|
||||
{
|
||||
DebuggableCore.MemoryCallbacks.Add(new MemoryCallback(domain, MemoryCallbackType.Execute, "Plugin Hook", cb, address, null));
|
||||
}
|
||||
}
|
||||
public void RemoveMemoryCallback(Action cb)
|
||||
{
|
||||
if (DebuggableCore.MemoryCallbacksAvailable())
|
||||
{
|
||||
DebuggableCore.MemoryCallbacks.Remove(cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public sealed class MemorySaveStateApi : IMemorySaveState
|
||||
{
|
||||
public MemorySaveStateApi()
|
||||
{ }
|
||||
|
||||
[RequiredService]
|
||||
private IStatable StatableCore { get; set; }
|
||||
|
||||
private readonly Dictionary<Guid, byte[]> _memorySavestates = new Dictionary<Guid, byte[]>();
|
||||
|
||||
public string SaveCoreStateToMemory()
|
||||
{
|
||||
var guid = Guid.NewGuid();
|
||||
var bytes = (byte[])StatableCore.SaveStateBinary().Clone();
|
||||
|
||||
_memorySavestates.Add(guid, bytes);
|
||||
|
||||
return guid.ToString();
|
||||
}
|
||||
|
||||
public void LoadCoreStateFromMemory(string identifier)
|
||||
{
|
||||
var guid = new Guid(identifier);
|
||||
|
||||
try
|
||||
{
|
||||
var state = _memorySavestates[guid];
|
||||
|
||||
using (var ms = new MemoryStream(state))
|
||||
using (var br = new BinaryReader(ms))
|
||||
{
|
||||
StatableCore.LoadStateBinary(br);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Unable to find the given savestate in memory");
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteState(string identifier)
|
||||
{
|
||||
var guid = new Guid(identifier);
|
||||
_memorySavestates.Remove(guid);
|
||||
}
|
||||
|
||||
public void ClearInMemoryStates()
|
||||
{
|
||||
_memorySavestates.Clear();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,288 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using BizHawk.Client.Common;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public sealed class MovieApi : IMovie
|
||||
{
|
||||
private static class MoviePluginStatic
|
||||
{
|
||||
public static string Filename()
|
||||
{
|
||||
return Global.MovieSession.Movie.Filename;
|
||||
}
|
||||
|
||||
public static bool GetReadOnly()
|
||||
{
|
||||
return Global.MovieSession.ReadOnly;
|
||||
}
|
||||
|
||||
public static ulong GetRerecordCount()
|
||||
{
|
||||
return Global.MovieSession.Movie.Rerecords;
|
||||
}
|
||||
|
||||
public static bool GetRerecordCounting()
|
||||
{
|
||||
return Global.MovieSession.Movie.IsCountingRerecords;
|
||||
}
|
||||
|
||||
public static bool IsLoaded()
|
||||
{
|
||||
return Global.MovieSession.Movie.IsActive;
|
||||
}
|
||||
|
||||
public static double Length()
|
||||
{
|
||||
return Global.MovieSession.Movie.FrameCount;
|
||||
}
|
||||
|
||||
public static string Mode()
|
||||
{
|
||||
if (Global.MovieSession.Movie.IsFinished)
|
||||
{
|
||||
return "FINISHED";
|
||||
}
|
||||
|
||||
if (Global.MovieSession.Movie.IsPlaying)
|
||||
{
|
||||
return "PLAY";
|
||||
}
|
||||
|
||||
if (Global.MovieSession.Movie.IsRecording)
|
||||
{
|
||||
return "RECORD";
|
||||
}
|
||||
|
||||
return "INACTIVE";
|
||||
}
|
||||
|
||||
public static void SetReadOnly(bool readOnly)
|
||||
{
|
||||
Global.MovieSession.ReadOnly = readOnly;
|
||||
}
|
||||
|
||||
public static void SetRerecordCount(double count)
|
||||
{
|
||||
// Lua numbers are always double, integer precision holds up
|
||||
// to 53 bits, so throw an error if it's bigger than that.
|
||||
const double PrecisionLimit = 9007199254740992d;
|
||||
|
||||
if (count > PrecisionLimit)
|
||||
{
|
||||
throw new Exception("Rerecord count exceeds Lua integer precision.");
|
||||
}
|
||||
|
||||
Global.MovieSession.Movie.Rerecords = (ulong)count;
|
||||
}
|
||||
|
||||
public static void SetRerecordCounting(bool counting)
|
||||
{
|
||||
Global.MovieSession.Movie.IsCountingRerecords = counting;
|
||||
}
|
||||
|
||||
public static void Stop()
|
||||
{
|
||||
Global.MovieSession.Movie.Stop();
|
||||
}
|
||||
|
||||
public static double GetFps()
|
||||
{
|
||||
if (Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
var movie = Global.MovieSession.Movie;
|
||||
var system = movie.HeaderEntries[HeaderKeys.PLATFORM];
|
||||
var pal = movie.HeaderEntries.ContainsKey(HeaderKeys.PAL) &&
|
||||
movie.HeaderEntries[HeaderKeys.PAL] == "1";
|
||||
|
||||
return new PlatformFrameRates()[system, pal];
|
||||
}
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
}
|
||||
public MovieApi()
|
||||
{ }
|
||||
|
||||
public bool StartsFromSavestate()
|
||||
{
|
||||
return Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.StartsFromSavestate;
|
||||
}
|
||||
|
||||
public bool StartsFromSaveram()
|
||||
{
|
||||
return Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.StartsFromSaveRam;
|
||||
}
|
||||
|
||||
public Dictionary<string, dynamic> GetInput(int frame)
|
||||
{
|
||||
if (!Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
Console.WriteLine("No movie loaded");
|
||||
return null;
|
||||
}
|
||||
|
||||
var input = new Dictionary<string, dynamic>();
|
||||
var adapter = Global.MovieSession.Movie.GetInputState(frame);
|
||||
|
||||
if (adapter == null)
|
||||
{
|
||||
Console.WriteLine("Can't get input of the last frame of the movie. Use the previous frame");
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach (var button in adapter.Definition.BoolButtons)
|
||||
{
|
||||
input[button] = adapter.IsPressed(button);
|
||||
}
|
||||
|
||||
foreach (var button in adapter.Definition.FloatControls)
|
||||
{
|
||||
input[button] = adapter.GetFloat(button);
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
public string GetInputAsMnemonic(int frame)
|
||||
{
|
||||
if (Global.MovieSession.Movie.IsActive && frame < Global.MovieSession.Movie.InputLogLength)
|
||||
{
|
||||
var lg = Global.MovieSession.LogGeneratorInstance();
|
||||
lg.SetSource(Global.MovieSession.Movie.GetInputState(frame));
|
||||
return lg.GenerateLogEntry();
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
public void Save(string filename = "")
|
||||
{
|
||||
if (!Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(filename))
|
||||
{
|
||||
filename += "." + Global.MovieSession.Movie.PreferredExtension;
|
||||
var test = new FileInfo(filename);
|
||||
if (test.Exists)
|
||||
{
|
||||
Console.WriteLine($"File {filename} already exists, will not overwrite");
|
||||
return;
|
||||
}
|
||||
|
||||
Global.MovieSession.Movie.Filename = filename;
|
||||
}
|
||||
|
||||
Global.MovieSession.Movie.Save();
|
||||
}
|
||||
|
||||
public Dictionary<string,string> GetHeader()
|
||||
{
|
||||
var table = new Dictionary<string,string>();
|
||||
if (Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
foreach (var kvp in Global.MovieSession.Movie.HeaderEntries)
|
||||
{
|
||||
table[kvp.Key] = kvp.Value;
|
||||
}
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
public List<string> GetComments()
|
||||
{
|
||||
var list = new List<string>(Global.MovieSession.Movie.Comments.Count);
|
||||
if (Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
for (int i = 0; i < Global.MovieSession.Movie.Comments.Count; i++)
|
||||
{
|
||||
list[i] = Global.MovieSession.Movie.Comments[i];
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public List<string> GetSubtitles()
|
||||
{
|
||||
var list = new List<string>(Global.MovieSession.Movie.Subtitles.Count);
|
||||
if (Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
for (int i = 0; i < Global.MovieSession.Movie.Subtitles.Count; i++)
|
||||
{
|
||||
list[i] = Global.MovieSession.Movie.Subtitles[i].ToString();
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public string Filename()
|
||||
{
|
||||
return MoviePluginStatic.Filename();
|
||||
}
|
||||
|
||||
public bool GetReadOnly()
|
||||
{
|
||||
return MoviePluginStatic.GetReadOnly();
|
||||
}
|
||||
|
||||
public ulong GetRerecordCount()
|
||||
{
|
||||
return MoviePluginStatic.GetRerecordCount();
|
||||
}
|
||||
|
||||
public bool GetRerecordCounting()
|
||||
{
|
||||
return MoviePluginStatic.GetRerecordCounting();
|
||||
}
|
||||
|
||||
public bool IsLoaded()
|
||||
{
|
||||
return MoviePluginStatic.IsLoaded();
|
||||
}
|
||||
|
||||
public double Length()
|
||||
{
|
||||
return MoviePluginStatic.Length();
|
||||
}
|
||||
|
||||
public string Mode()
|
||||
{
|
||||
return MoviePluginStatic.Mode();
|
||||
}
|
||||
|
||||
public void SetReadOnly(bool readOnly)
|
||||
{
|
||||
MoviePluginStatic.SetReadOnly(readOnly);
|
||||
}
|
||||
|
||||
public void SetRerecordCount(double count)
|
||||
{
|
||||
MoviePluginStatic.SetRerecordCount(count);
|
||||
}
|
||||
|
||||
public void SetRerecordCounting(bool counting)
|
||||
{
|
||||
MoviePluginStatic.SetRerecordCounting(counting);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
MoviePluginStatic.Stop();
|
||||
}
|
||||
|
||||
public double GetFps()
|
||||
{
|
||||
return MoviePluginStatic.GetFps();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public abstract class PluginBase : IPlugin
|
||||
{
|
||||
/// <summary>
|
||||
/// The base class from which all
|
||||
/// plugins will be derived
|
||||
///
|
||||
/// Actual plugins should implement
|
||||
/// one of the below callback methods
|
||||
/// or register memory callbacks in
|
||||
/// their Init function.
|
||||
/// </summary>
|
||||
protected IApiContainer _api;
|
||||
|
||||
public PluginBase() { }
|
||||
|
||||
public abstract string Name { get; }
|
||||
public abstract string Description { get; }
|
||||
|
||||
public bool Enabled => Running;
|
||||
public bool Paused => !Running;
|
||||
|
||||
public bool Running { get; set; }
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
Running = false;
|
||||
}
|
||||
|
||||
public void Toggle()
|
||||
{
|
||||
Running = !Running;
|
||||
}
|
||||
|
||||
public virtual void PreFrameCallback() { }
|
||||
public virtual void PostFrameCallback() { }
|
||||
public virtual void SaveStateCallback(string name) { }
|
||||
public virtual void LoadStateCallback(string name) { }
|
||||
public virtual void InputPollCallback() { }
|
||||
public virtual void ExitCallback() { }
|
||||
public virtual void Init (IApiContainer api)
|
||||
{
|
||||
_api = api;
|
||||
Running = true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data.SQLite;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public sealed class SqlApi : ISql
|
||||
{
|
||||
public SqlApi() : base()
|
||||
{ }
|
||||
|
||||
SQLiteConnection m_dbConnection;
|
||||
string connectionString;
|
||||
|
||||
public string CreateDatabase(string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
SQLiteConnection.CreateFile(name);
|
||||
return "Database Created Successfully";
|
||||
}
|
||||
catch (SQLiteException sqlEX)
|
||||
{
|
||||
return sqlEX.Message;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public string OpenDatabase(string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
SQLiteConnectionStringBuilder connBuilder = new SQLiteConnectionStringBuilder();
|
||||
connBuilder.DataSource = name;
|
||||
connBuilder.Version = 3; //SQLite version
|
||||
connBuilder.JournalMode = SQLiteJournalModeEnum.Wal; //Allows for reads and writes to happen at the same time
|
||||
connBuilder.DefaultIsolationLevel = System.Data.IsolationLevel.ReadCommitted; //This only helps make the database lock left. May be pointless now
|
||||
connBuilder.SyncMode = SynchronizationModes.Off; //This shortens the delay for do synchronous calls.
|
||||
m_dbConnection = new SQLiteConnection(connBuilder.ToString());
|
||||
connectionString = connBuilder.ToString();
|
||||
m_dbConnection.Open();
|
||||
m_dbConnection.Close();
|
||||
return "Database Opened Successfully";
|
||||
}
|
||||
catch (SQLiteException sqlEX)
|
||||
{
|
||||
return sqlEX.Message;
|
||||
}
|
||||
}
|
||||
|
||||
public string WriteCommand(string query = "")
|
||||
{
|
||||
if (query == "")
|
||||
{
|
||||
return "query is empty";
|
||||
}
|
||||
try
|
||||
{
|
||||
m_dbConnection.Open();
|
||||
string sql = query;
|
||||
SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection);
|
||||
command.ExecuteNonQuery();
|
||||
m_dbConnection.Close();
|
||||
|
||||
return "Command ran successfully";
|
||||
|
||||
}
|
||||
catch (NullReferenceException nullEX)
|
||||
{
|
||||
return "Database not open.";
|
||||
}
|
||||
catch (SQLiteException sqlEX)
|
||||
{
|
||||
m_dbConnection.Close();
|
||||
return sqlEX.Message;
|
||||
}
|
||||
}
|
||||
|
||||
public dynamic ReadCommand(string query = "")
|
||||
{
|
||||
if (query == "")
|
||||
{
|
||||
return "query is empty";
|
||||
}
|
||||
try
|
||||
{
|
||||
var table = new Dictionary<string, object>();
|
||||
m_dbConnection.Open();
|
||||
string sql = "PRAGMA read_uncommitted =1;" + query;
|
||||
SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection);
|
||||
SQLiteDataReader reader = command.ExecuteReader();
|
||||
bool rows = reader.HasRows;
|
||||
long rowCount = 0;
|
||||
var columns = new List<string>();
|
||||
for (int i = 0; i < reader.FieldCount; ++i) //Add all column names into list
|
||||
{
|
||||
columns.Add(reader.GetName(i));
|
||||
}
|
||||
while (reader.Read())
|
||||
{
|
||||
for (int i = 0; i < reader.FieldCount; ++i)
|
||||
{
|
||||
table[columns[i] + " " + rowCount.ToString()] = reader.GetValue(i);
|
||||
}
|
||||
rowCount += 1;
|
||||
}
|
||||
reader.Close();
|
||||
m_dbConnection.Close();
|
||||
if (rows == false)
|
||||
{
|
||||
return "No rows found";
|
||||
}
|
||||
|
||||
return table;
|
||||
|
||||
}
|
||||
catch (NullReferenceException)
|
||||
{
|
||||
return "Database not opened.";
|
||||
}
|
||||
catch (SQLiteException sqlEX)
|
||||
{
|
||||
m_dbConnection.Close();
|
||||
return sqlEX.Message;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
using BizHawk.Client.Common;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public sealed class UserDataApi : IUserData
|
||||
{
|
||||
public UserDataApi() : base()
|
||||
{ }
|
||||
|
||||
public void Set(string name, object value)
|
||||
{
|
||||
if (value != null)
|
||||
{
|
||||
var t = value.GetType();
|
||||
if (!t.IsPrimitive && t != typeof(string))
|
||||
{
|
||||
throw new InvalidOperationException("Invalid type for userdata");
|
||||
}
|
||||
}
|
||||
|
||||
Global.UserBag[name] = value;
|
||||
}
|
||||
|
||||
public object Get(string key)
|
||||
{
|
||||
if (Global.UserBag.ContainsKey(key))
|
||||
{
|
||||
return Global.UserBag[key];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Global.UserBag.Clear();
|
||||
}
|
||||
|
||||
public bool Remove(string key)
|
||||
{
|
||||
return Global.UserBag.Remove(key);
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
return Global.UserBag.ContainsKey(key);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Common.ReflectionExtensions;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
/// <summary>
|
||||
/// injects Apis into other classes
|
||||
/// </summary>
|
||||
public static class ApiInjector
|
||||
{
|
||||
/// <summary>
|
||||
/// clears all Apis from a target
|
||||
/// </summary>
|
||||
public static void ClearApis(object target)
|
||||
{
|
||||
Type targetType = target.GetType();
|
||||
object[] tmp = new object[1];
|
||||
|
||||
foreach (var propinfo in
|
||||
targetType.GetPropertiesWithAttrib(typeof(RequiredApiAttribute))
|
||||
.Concat(targetType.GetPropertiesWithAttrib(typeof(OptionalApiAttribute))))
|
||||
{
|
||||
propinfo.GetSetMethod(true).Invoke(target, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Feeds the target its required Apis.
|
||||
/// </summary>
|
||||
/// <returns>false if update failed</returns>
|
||||
public static bool UpdateApis(IExternalApiProvider source, object target)
|
||||
{
|
||||
Type targetType = target.GetType();
|
||||
object[] tmp = new object[1];
|
||||
|
||||
foreach (var propinfo in targetType.GetPropertiesWithAttrib(typeof(RequiredApiAttribute)))
|
||||
{
|
||||
tmp[0] = source.GetApi(propinfo.PropertyType);
|
||||
if (tmp[0] == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
propinfo.GetSetMethod(true).Invoke(target, tmp);
|
||||
}
|
||||
|
||||
foreach (var propinfo in targetType.GetPropertiesWithAttrib(typeof(OptionalApiAttribute)))
|
||||
{
|
||||
tmp[0] = source.GetApi(propinfo.PropertyType);
|
||||
propinfo.GetSetMethod(true).Invoke(target, tmp);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a target is available, considering its dependencies
|
||||
/// and the Apis provided by the emulator core.
|
||||
/// </summary>
|
||||
public static bool IsAvailable(IExternalApiProvider source, Type targetType)
|
||||
{
|
||||
return targetType.GetPropertiesWithAttrib(typeof(RequiredApiAttribute))
|
||||
.Select(pi => pi.PropertyType)
|
||||
.All(source.HasApi);
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class RequiredApiAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class OptionalApiAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
/// <summary>
|
||||
/// A generic implementation of IExternalApi provider that provides
|
||||
/// this functionality to any core.
|
||||
/// The provider will scan an IExternal and register all IExternalApis
|
||||
/// that the core object itself implements. In addition it provides
|
||||
/// a Register() method to allow the core to pass in any additional Apis
|
||||
/// </summary>
|
||||
/// <seealso cref="IExternalApiProvider"/>
|
||||
public class BasicApiProvider : IExternalApiProvider
|
||||
{
|
||||
private readonly Dictionary<Type, IExternalApi> _Apis = new Dictionary<Type, IExternalApi>();
|
||||
|
||||
public BasicApiProvider(IApiContainer container)
|
||||
{
|
||||
// simplified logic here doesn't scan for possible Apis; just adds what it knows is implemented by the PluginApi
|
||||
// this removes the possibility of automagically picking up a Api in a nested class, (find the type, then
|
||||
// find the field), but we're going to keep such logic out of the basic provider. Anything the passed
|
||||
// container doesn't implement directly needs to be added with Register()
|
||||
// this also fully allows apis that are not IExternalApi
|
||||
var libs = container.Libraries;
|
||||
|
||||
_Apis = libs;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// the client can call this to register an additional Api
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The <seealso cref="IExternalApi"/> to register</typeparam>
|
||||
public void Register<T>(T api)
|
||||
where T : IExternalApi
|
||||
{
|
||||
if (api == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(api));
|
||||
}
|
||||
|
||||
_Apis[typeof(T)] = api;
|
||||
}
|
||||
|
||||
public T GetApi<T>()
|
||||
where T : IExternalApi
|
||||
{
|
||||
return (T)GetApi(typeof(T));
|
||||
}
|
||||
|
||||
public object GetApi(Type t)
|
||||
{
|
||||
IExternalApi Api;
|
||||
KeyValuePair<Type, IExternalApi>[] k = _Apis.Where(kvp => t.IsAssignableFrom(kvp.Key)).ToArray();
|
||||
if (k.Length > 0)
|
||||
{
|
||||
return k[0].Value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public bool HasApi<T>()
|
||||
where T : IExternalApi
|
||||
{
|
||||
return HasApi(typeof(T));
|
||||
}
|
||||
|
||||
public bool HasApi(Type t)
|
||||
{
|
||||
return _Apis.ContainsKey(t);
|
||||
}
|
||||
|
||||
public IEnumerable<Type> AvailableApis
|
||||
{
|
||||
get
|
||||
{
|
||||
return _Apis.Select(d => d.Key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ using System.Reflection;
|
|||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
|
||||
using BizHawk.Emulation.Cores.PCEngine;
|
||||
using BizHawk.Emulation.Cores.Sega.MasterSystem;
|
||||
|
@ -21,6 +22,9 @@ namespace BizHawk.Client.ApiHawk
|
|||
{
|
||||
#region Fields
|
||||
|
||||
private static IEmulator Emulator;
|
||||
private static IVideoProvider VideoProvider;
|
||||
|
||||
private static readonly Assembly clientAssembly;
|
||||
private static readonly object clientMainFormInstance;
|
||||
private static readonly Type mainFormClass;
|
||||
|
@ -68,24 +72,57 @@ namespace BizHawk.Client.ApiHawk
|
|||
mainFormClass = clientAssembly.GetType("BizHawk.Client.EmuHawk.MainForm");
|
||||
}
|
||||
|
||||
public static void UpdateEmulatorAndVP(IEmulator emu = null)
|
||||
{
|
||||
Emulator = emu;
|
||||
VideoProvider = Emulation.Common.IEmulatorExtensions.Extensions.AsVideoProviderOrDefault(emu);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Methods
|
||||
|
||||
#region Helpers
|
||||
|
||||
private static void InvokeMainFormMethod(string name, dynamic[] paramList = null)
|
||||
{
|
||||
List<Type> typeList = new List<Type>();
|
||||
MethodInfo method;
|
||||
if (paramList != null)
|
||||
{
|
||||
foreach (var obj in paramList)
|
||||
{
|
||||
typeList.Add(obj.GetType());
|
||||
}
|
||||
method = mainFormClass.GetMethod(name, typeList.ToArray());
|
||||
}
|
||||
else method = mainFormClass.GetMethod(name);
|
||||
method.Invoke(clientMainFormInstance, paramList);
|
||||
}
|
||||
|
||||
private static object GetMainFormField(string name)
|
||||
{
|
||||
return mainFormClass.GetField(name);
|
||||
}
|
||||
|
||||
private static void SetMainFormField(string name, object value)
|
||||
{
|
||||
mainFormClass.GetField(name).SetValue(clientMainFormInstance, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Public
|
||||
/// <summary>
|
||||
/// THE FrameAdvance stuff
|
||||
/// </summary>
|
||||
public static void DoFrameAdvance()
|
||||
{
|
||||
MethodInfo method = mainFormClass.GetMethod("FrameAdvance");
|
||||
method.Invoke(clientMainFormInstance, null);
|
||||
InvokeMainFormMethod("FrameAdvance", null);
|
||||
|
||||
method = mainFormClass.GetMethod("StepRunLoop_Throttle", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
method.Invoke(clientMainFormInstance, null);
|
||||
InvokeMainFormMethod("StepRunLoop_Throttle", null);
|
||||
|
||||
method = mainFormClass.GetMethod("Render", BindingFlags.NonPublic | BindingFlags.Instance);
|
||||
method.Invoke(clientMainFormInstance, null);
|
||||
InvokeMainFormMethod("Render", null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -124,8 +161,7 @@ namespace BizHawk.Client.ApiHawk
|
|||
/// <param name="name">Savetate friendly name</param>
|
||||
public static void LoadState(string name)
|
||||
{
|
||||
MethodInfo method = mainFormClass.GetMethod("LoadState");
|
||||
method.Invoke(clientMainFormInstance, new object[] { Path.Combine(PathManager.GetSaveStatePath(Global.Game), string.Format("{0}.{1}", name, "State")), name, false, false });
|
||||
InvokeMainFormMethod("LoadState", new object[] { Path.Combine(PathManager.GetSaveStatePath(Global.Game), string.Format("{0}.{1}", name, "State")), name, false, false });
|
||||
}
|
||||
|
||||
|
||||
|
@ -194,12 +230,11 @@ namespace BizHawk.Client.ApiHawk
|
|||
/// <summary>
|
||||
/// Raise when a rom is successfully Loaded
|
||||
/// </summary>
|
||||
public static void OnRomLoaded()
|
||||
public static void OnRomLoaded(IEmulator emu)
|
||||
{
|
||||
if (RomLoaded != null)
|
||||
{
|
||||
RomLoaded(null, EventArgs.Empty);
|
||||
}
|
||||
Emulator = emu;
|
||||
VideoProvider = Emulation.Common.IEmulatorExtensions.Extensions.AsVideoProviderOrDefault(emu);
|
||||
RomLoaded?.Invoke(null, EventArgs.Empty);
|
||||
|
||||
allJoypads = new List<Joypad>(RunningSystem.MaxControllers);
|
||||
for (int i = 1; i <= RunningSystem.MaxControllers; i++)
|
||||
|
@ -215,10 +250,55 @@ namespace BizHawk.Client.ApiHawk
|
|||
/// <param name="name">Savetate friendly name</param>
|
||||
public static void SaveState(string name)
|
||||
{
|
||||
MethodInfo method = mainFormClass.GetMethod("SaveState");
|
||||
method.Invoke(clientMainFormInstance, new object[] { Path.Combine(PathManager.GetSaveStatePath(Global.Game), string.Format("{0}.{1}", name, "State")), name, false });
|
||||
InvokeMainFormMethod("SaveState", new object[] { Path.Combine(PathManager.GetSaveStatePath(Global.Game), string.Format("{0}.{1}", name, "State")), name, false });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements
|
||||
/// </summary>
|
||||
/// <param name="left">Left padding</param>
|
||||
/// <param name="top">Top padding</param>
|
||||
/// <param name="right">Right padding</param>
|
||||
/// <param name="bottom">Bottom padding</param>
|
||||
public static void SetGameExtraPadding(int left, int top, int right, int bottom)
|
||||
{
|
||||
FieldInfo f = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin").GetField("DisplayManager");
|
||||
object displayManager = f.GetValue(null);
|
||||
f = f.FieldType.GetField("GameExtraPadding");
|
||||
f.SetValue(displayManager, new Padding(left, top, right, bottom));
|
||||
|
||||
InvokeMainFormMethod("FrameBufferResized");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements
|
||||
/// </summary>
|
||||
/// <param name="left">Left padding</param>
|
||||
public static void SetGameExtraPadding(int left)
|
||||
{
|
||||
SetGameExtraPadding(left, 0, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements
|
||||
/// </summary>
|
||||
/// <param name="left">Left padding</param>
|
||||
/// <param name="top">Top padding</param>
|
||||
public static void SetGameExtraPadding(int left, int top)
|
||||
{
|
||||
SetGameExtraPadding(left, top, 0, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements
|
||||
/// </summary>
|
||||
/// <param name="left">Left padding</param>
|
||||
/// <param name="top">Top padding</param>
|
||||
/// <param name="right">Right padding</param>
|
||||
public static void SetGameExtraPadding(int left, int top, int right)
|
||||
{
|
||||
SetGameExtraPadding(left, top, right, 0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements
|
||||
|
@ -234,8 +314,7 @@ namespace BizHawk.Client.ApiHawk
|
|||
f = f.FieldType.GetField("ClientExtraPadding");
|
||||
f.SetValue(displayManager, new Padding(left, top, right, bottom));
|
||||
|
||||
MethodInfo resize = mainFormClass.GetMethod("FrameBufferResized");
|
||||
resize.Invoke(clientMainFormInstance, null);
|
||||
InvokeMainFormMethod("FrameBufferResized");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -268,7 +347,6 @@ namespace BizHawk.Client.ApiHawk
|
|||
SetExtraPadding(left, top, right, 0);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Set inputs in specified <see cref="Joypad"/> to specified player
|
||||
/// </summary>
|
||||
|
@ -327,8 +405,7 @@ namespace BizHawk.Client.ApiHawk
|
|||
/// </summary>
|
||||
public static void UnpauseEmulation()
|
||||
{
|
||||
MethodInfo method = mainFormClass.GetMethod("UnpauseEmulator");
|
||||
method.Invoke(clientMainFormInstance, null);
|
||||
InvokeMainFormMethod("UnpauseEmulator", null);
|
||||
}
|
||||
#endregion Public
|
||||
|
||||
|
@ -375,6 +452,275 @@ namespace BizHawk.Client.ApiHawk
|
|||
}
|
||||
}
|
||||
|
||||
public static void CloseEmulator()
|
||||
{
|
||||
InvokeMainFormMethod("CloseEmulator");
|
||||
}
|
||||
|
||||
public static void CloseEmulatorWithCode(int exitCode)
|
||||
{
|
||||
InvokeMainFormMethod("CloseEmulator", new object[] {exitCode});
|
||||
}
|
||||
|
||||
public static int BorderHeight()
|
||||
{
|
||||
var point = new System.Drawing.Point(0, 0);
|
||||
Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin");
|
||||
FieldInfo f = t.GetField("DisplayManager");
|
||||
object displayManager = f.GetValue(null);
|
||||
MethodInfo m = t.GetMethod("TransFormPoint");
|
||||
point = (System.Drawing.Point) m.Invoke(displayManager, new object[] { point });
|
||||
return point.Y;
|
||||
}
|
||||
|
||||
public static int BorderWidth()
|
||||
{
|
||||
var point = new System.Drawing.Point(0, 0);
|
||||
Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin");
|
||||
FieldInfo f = t.GetField("DisplayManager");
|
||||
object displayManager = f.GetValue(null);
|
||||
MethodInfo m = t.GetMethod("TransFormPoint");
|
||||
point = (System.Drawing.Point)m.Invoke(displayManager, new object[] { point });
|
||||
return point.X;
|
||||
}
|
||||
|
||||
public static int BufferHeight()
|
||||
{
|
||||
return VideoProvider.BufferHeight;
|
||||
}
|
||||
|
||||
public static int BufferWidth()
|
||||
{
|
||||
return VideoProvider.BufferWidth;
|
||||
}
|
||||
|
||||
public static void ClearAutohold()
|
||||
{
|
||||
InvokeMainFormMethod("ClearHolds");
|
||||
}
|
||||
|
||||
public static void CloseRom()
|
||||
{
|
||||
InvokeMainFormMethod("CloseRom");
|
||||
}
|
||||
|
||||
public static void DisplayMessages(bool value)
|
||||
{
|
||||
Global.Config.DisplayMessages = value;
|
||||
}
|
||||
|
||||
public static void EnableRewind(bool enabled)
|
||||
{
|
||||
InvokeMainFormMethod("EnableRewind", new object[] {enabled});
|
||||
}
|
||||
|
||||
public static void FrameSkip(int numFrames)
|
||||
{
|
||||
if (numFrames > 0)
|
||||
{
|
||||
Global.Config.FrameSkip = numFrames;
|
||||
InvokeMainFormMethod("FrameSkipMessage");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid frame skip value");
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetTargetScanlineIntensity()
|
||||
{
|
||||
return Global.Config.TargetScanlineFilterIntensity;
|
||||
}
|
||||
|
||||
public static int GetWindowSize()
|
||||
{
|
||||
return Global.Config.TargetZoomFactors[Emulator.SystemId];
|
||||
}
|
||||
|
||||
public static void SetSoundOn(bool enable)
|
||||
{
|
||||
Global.Config.SoundEnabled = enable;
|
||||
}
|
||||
|
||||
public static bool GetSoundOn()
|
||||
{
|
||||
return Global.Config.SoundEnabled;
|
||||
}
|
||||
|
||||
public static bool IsPaused()
|
||||
{
|
||||
return (bool) GetMainFormField("EmulatorPaused");
|
||||
}
|
||||
|
||||
public static bool IsTurbo()
|
||||
{
|
||||
return (bool)GetMainFormField("IsTurboing");
|
||||
}
|
||||
|
||||
public static bool IsSeeking()
|
||||
{
|
||||
return (bool)GetMainFormField("IsSeeking");
|
||||
}
|
||||
|
||||
public static void OpenRom(string path)
|
||||
{
|
||||
var ioa = OpenAdvancedSerializer.ParseWithLegacy(path);
|
||||
Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin.MainForm.LoadRomArgs");
|
||||
object o = Activator.CreateInstance(t);
|
||||
t.GetField("OpenAdvanced").SetValue(o, ioa);
|
||||
|
||||
InvokeMainFormMethod("LoadRom", new object[] {path, o});
|
||||
}
|
||||
|
||||
public static void Pause()
|
||||
{
|
||||
InvokeMainFormMethod("PauseEmulator");
|
||||
}
|
||||
|
||||
public static void PauseAv()
|
||||
{
|
||||
SetMainFormField("PauseAvi", true);
|
||||
}
|
||||
|
||||
public static void RebootCore()
|
||||
{
|
||||
InvokeMainFormMethod("RebootCore");
|
||||
}
|
||||
|
||||
public static void SaveRam()
|
||||
{
|
||||
InvokeMainFormMethod("FlushSaveRAM");
|
||||
}
|
||||
|
||||
public static int ScreenHeight()
|
||||
{
|
||||
Type t = GetMainFormField("PresentationPanel").GetType();
|
||||
object o = GetMainFormField("PresentationPanel");
|
||||
o = t.GetField("NativeSize").GetValue(o);
|
||||
t = t.GetField("NativeSize").GetType();
|
||||
|
||||
return (int) t.GetField("Height").GetValue(o);
|
||||
}
|
||||
|
||||
public static void Screenshot(string path = null)
|
||||
{
|
||||
if (path == null)
|
||||
{
|
||||
InvokeMainFormMethod("TakeScreenshot");
|
||||
}
|
||||
else
|
||||
{
|
||||
InvokeMainFormMethod("TakeScreenshot", new object[] {path});
|
||||
}
|
||||
}
|
||||
|
||||
public static void ScreenshotToClipboard()
|
||||
{
|
||||
InvokeMainFormMethod("TakeScreenshotToClipboard");
|
||||
}
|
||||
|
||||
public static void SetTargetScanlineIntensity(int val)
|
||||
{
|
||||
Global.Config.TargetScanlineFilterIntensity = val;
|
||||
}
|
||||
|
||||
public static void SetScreenshotOSD(bool value)
|
||||
{
|
||||
Global.Config.Screenshot_CaptureOSD = value;
|
||||
}
|
||||
|
||||
public static int ScreenWidth()
|
||||
{
|
||||
Type t = GetMainFormField("PresentationPanel").GetType();
|
||||
object o = GetMainFormField("PresentationPanel");
|
||||
o = t.GetField("NativeSize").GetValue(o);
|
||||
t = t.GetField("NativeSize").GetType();
|
||||
|
||||
return (int) t.GetField("Width").GetValue(o);
|
||||
}
|
||||
|
||||
public static void SetWindowSize(int size)
|
||||
{
|
||||
if (size == 1 || size == 2 || size == 3 || size == 4 || size == 5 || size == 10)
|
||||
{
|
||||
Global.Config.TargetZoomFactors[Emulator.SystemId] = size;
|
||||
InvokeMainFormMethod("FrameBufferResized");
|
||||
Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin");
|
||||
FieldInfo f = t.GetField("OSD");
|
||||
object osd = f.GetValue(null);
|
||||
t = f.GetType();
|
||||
MethodInfo m = t.GetMethod("AddMessage");
|
||||
m.Invoke(osd, new Object[] { "Window size set to " + size + "x" });
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid window size");
|
||||
}
|
||||
}
|
||||
|
||||
public static void SpeedMode(int percent)
|
||||
{
|
||||
if (percent > 0 && percent < 6400)
|
||||
{
|
||||
InvokeMainFormMethod("ClickSpeedItem", new object[] {percent});
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Invalid speed value");
|
||||
}
|
||||
}
|
||||
|
||||
public static void TogglePause()
|
||||
{
|
||||
InvokeMainFormMethod("TogglePause");
|
||||
}
|
||||
|
||||
public static int TransformPointX(int x)
|
||||
{
|
||||
var point = new System.Drawing.Point(x, 0);
|
||||
Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin");
|
||||
FieldInfo f = t.GetField("DisplayManager");
|
||||
object displayManager = f.GetValue(null);
|
||||
MethodInfo m = t.GetMethod("TransFormPoint");
|
||||
point = (System.Drawing.Point)m.Invoke(displayManager, new object[] { point });
|
||||
return point.X;
|
||||
}
|
||||
|
||||
public static int TransformPointY(int y)
|
||||
{
|
||||
var point = new System.Drawing.Point(0, y);
|
||||
Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin");
|
||||
FieldInfo f = t.GetField("DisplayManager");
|
||||
object displayManager = f.GetValue(null);
|
||||
MethodInfo m = t.GetMethod("TransFormPoint");
|
||||
point = (System.Drawing.Point)m.Invoke(displayManager, new object[] { point });
|
||||
return point.Y;
|
||||
}
|
||||
|
||||
public static void Unpause()
|
||||
{
|
||||
InvokeMainFormMethod("UnpauseEmulator");
|
||||
}
|
||||
|
||||
public static void UnpauseAv()
|
||||
{
|
||||
SetMainFormField("PauseAvi", false);
|
||||
}
|
||||
|
||||
public static int Xpos()
|
||||
{
|
||||
object o = GetMainFormField("DesktopLocation");
|
||||
Type t = mainFormClass.GetField("DesktopLocation").GetType();
|
||||
return (int)t.GetField("X").GetValue(o);
|
||||
}
|
||||
|
||||
public static int Ypos()
|
||||
{
|
||||
object o = GetMainFormField("DesktopLocation");
|
||||
Type t = mainFormClass.GetField("DesktopLocation").GetType();
|
||||
return (int)t.GetField("Y").GetValue(o);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
@ -427,11 +773,11 @@ namespace BizHawk.Client.ApiHawk
|
|||
}
|
||||
else
|
||||
{
|
||||
return SystemInfo.DualGB;
|
||||
return SystemInfo.DualGB;
|
||||
}
|
||||
|
||||
default:
|
||||
return SystemInfo.FindByCoreSystem(SystemIdConverter.Convert(Global.Emulator.SystemId));
|
||||
return SystemInfo.FindByCoreSystem(SystemIdConverter.Convert(Global.Emulator.SystemId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface IApiContainer
|
||||
{
|
||||
Dictionary<Type, IExternalApi> Libraries { get; set; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface IComm : IExternalApi
|
||||
{
|
||||
#region Sockets
|
||||
string SocketServerScreenShot();
|
||||
string SocketServerScreenShotResponse();
|
||||
string SocketServerSend(string SendString);
|
||||
string SocketServerResponse();
|
||||
bool SocketServerSuccessful();
|
||||
void SocketServerSetTimeout(int timeout);
|
||||
#endregion
|
||||
|
||||
#region MemoryMappedFiles
|
||||
void MmfSetFilename(string filename);
|
||||
string MmfSetFilename();
|
||||
int MmfScreenshot();
|
||||
int MmfWrite(string mmf_filename, string outputString);
|
||||
string MmfRead(string mmf_filename, int expectedSize);
|
||||
#endregion
|
||||
|
||||
#region HTTP
|
||||
string HttpTest();
|
||||
string HttpTestGet();
|
||||
string HttpGet(string url);
|
||||
string HttpPost(string url, string payload);
|
||||
string HttpPostScreenshot();
|
||||
void HttpSetTimeout(int timeout);
|
||||
void HttpSetPostUrl(string url);
|
||||
void HttpSetGetUrl(string url);
|
||||
string HttpGetPostUrl();
|
||||
string HttpGetGetUrl();
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface IEmu : IExternalApi
|
||||
{
|
||||
Action FrameAdvanceCallback { get; set; }
|
||||
Action YieldCallback { get; set; }
|
||||
void DisplayVsync(bool enabled);
|
||||
void FrameAdvance();
|
||||
int FrameCount();
|
||||
object Disassemble(uint pc, string name = "");
|
||||
ulong? GetRegister(string name);
|
||||
Dictionary<string, ulong> GetRegisters();
|
||||
void SetRegister(string register, int value);
|
||||
long TotalExecutedycles();
|
||||
string GetSystemId();
|
||||
bool IsLagged();
|
||||
void SetIsLagged(bool value = true);
|
||||
int LagCount();
|
||||
void SetLagCount(int count);
|
||||
void LimitFramerate(bool enabled);
|
||||
void MinimizeFrameskip(bool enabled);
|
||||
void Yield();
|
||||
string GetDisplayType();
|
||||
string GetBoardName();
|
||||
object GetSettings();
|
||||
bool PutSettings(object settings);
|
||||
void SetRenderPlanes(params bool[] param);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface specifies that a client exposes a given interface, such as <seealso cref="IDebuggable"/>,
|
||||
/// for use by external tools.
|
||||
/// </summary>
|
||||
public interface IExternalApi
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface IGameInfo : IExternalApi
|
||||
{
|
||||
string GetRomName();
|
||||
string GetRomHash();
|
||||
bool InDatabase();
|
||||
string GetStatus();
|
||||
bool IsStatusBad();
|
||||
string GetBoardType();
|
||||
Dictionary<string, string> GetOptions();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface IGui : IExternalApi
|
||||
{
|
||||
#region Gui API
|
||||
void ToggleCompositingMode();
|
||||
ImageAttributes GetAttributes();
|
||||
void SetAttributes(ImageAttributes a);
|
||||
void DrawNew(string name, bool? clear = true);
|
||||
void DrawFinish();
|
||||
bool HasGUISurface { get; }
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
void SetPadding(int all);
|
||||
void SetPadding(int x, int y);
|
||||
void SetPadding(int l, int t, int r, int b);
|
||||
Padding GetPadding();
|
||||
#endregion
|
||||
|
||||
void AddMessage(string message);
|
||||
void ClearGraphics();
|
||||
void ClearText();
|
||||
void SetDefaultForegroundColor(Color color);
|
||||
void SetDefaultBackgroundColor(Color color);
|
||||
void SetDefaultTextBackground(Color color);
|
||||
void SetDefaultPixelFont(string fontfamily);
|
||||
void DrawBezier(Point p1, Point p2, Point p3, Point p4, Color? color = null);
|
||||
void DrawBeziers(Point[] points, Color? color = null);
|
||||
void DrawBox(int x, int y, int x2, int y2, Color? line = null, Color? background = null);
|
||||
void DrawEllipse(int x, int y, int width, int height, Color? line = null, Color? background = null);
|
||||
void DrawIcon(string path, int x, int y, int? width = null, int? height = null);
|
||||
void DrawImage(string path, int x, int y, int? width = null, int? height = null, bool cache = true);
|
||||
void ClearImageCache();
|
||||
void DrawImageRegion(string path, int source_x, int source_y, int source_width, int source_height, int dest_x, int dest_y, int? dest_width = null, int? dest_height = null);
|
||||
void DrawLine(int x1, int y1, int x2, int y2, Color? color = null);
|
||||
void DrawAxis(int x, int y, int size, Color? color = null);
|
||||
void DrawPie(int x, int y, int width, int height, int startangle, int sweepangle, Color? line = null, Color? background = null);
|
||||
void DrawPixel(int x, int y, Color? color = null);
|
||||
void DrawPolygon(Point[] points, Color? line = null, Color? background = null);
|
||||
void DrawRectangle(int x, int y, int width, int height, Color? line = null, Color? background = null);
|
||||
void DrawString(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, int? fontsize = null,
|
||||
string fontfamily = null, string fontstyle = null, string horizalign = null, string vertalign = null);
|
||||
void DrawText(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, string fontfamily = null);
|
||||
void Text(int x, int y, string message, Color? forecolor = null, string anchor = null);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface IInput : IExternalApi
|
||||
{
|
||||
Dictionary<string, bool> Get();
|
||||
Dictionary<string, dynamic> GetMouse();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface IJoypad : IExternalApi
|
||||
{
|
||||
Dictionary<string, dynamic> Get(int? controller = null);
|
||||
|
||||
// TODO: what about float controls?
|
||||
Dictionary<string, dynamic> GetImmediate();
|
||||
void SetFromMnemonicStr(string inputLogEntry);
|
||||
void Set(Dictionary<string, bool> buttons, int? controller = null);
|
||||
void Set(string button, bool? state = null, int? controller = null);
|
||||
void SetAnalog(Dictionary<string, float> controls, object controller = null);
|
||||
void SetAnalog(string control, float? value = null, object controller = null);
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface IMem : IExternalApi
|
||||
{
|
||||
void SetBigEndian(bool enabled = true);
|
||||
|
||||
#region Domains
|
||||
List<string> GetMemoryDomainList();
|
||||
uint GetMemoryDomainSize(string name = "");
|
||||
string GetCurrentMemoryDomain();
|
||||
uint GetCurrentMemoryDomainSize();
|
||||
bool UseMemoryDomain(string domain);
|
||||
string HashRegion(long addr, int count, string domain = null);
|
||||
#endregion
|
||||
#region Read
|
||||
#region Special and Legacy Methods
|
||||
uint ReadByte(long addr, string domain = null);
|
||||
List<byte> ReadByteRange(long addr, int length, string domain = null);
|
||||
float ReadFloat(long addr, string domain = null);
|
||||
#endregion
|
||||
#region Signed
|
||||
int ReadS8(long addr, string domain = null);
|
||||
int ReadS16(long addr, string domain = null);
|
||||
int ReadS24(long addr, string domain = null);
|
||||
int ReadS32(long addr, string domain = null);
|
||||
#endregion
|
||||
#region Unsigned
|
||||
uint ReadU8(long addr, string domain = null);
|
||||
uint ReadU16(long addr, string domain = null);
|
||||
uint ReadU24(long addr, string domain = null);
|
||||
uint ReadU32(long addr, string domain = null);
|
||||
#endregion
|
||||
#endregion
|
||||
#region Write
|
||||
#region Special and Legacy Methods
|
||||
void WriteByte(long addr, uint value, string domain = null);
|
||||
void WriteByteRange(long addr, List<byte> memoryblock, string domain = null);
|
||||
void WriteFloat(long addr, double value, string domain = null);
|
||||
#endregion
|
||||
#region Signed
|
||||
void WriteS8(long addr, int value, string domain = null);
|
||||
void WriteS16(long addr, int value, string domain = null);
|
||||
void WriteS24(long addr, int value, string domain = null);
|
||||
void WriteS32(long addr, int value, string domain = null);
|
||||
#endregion
|
||||
#region Unigned
|
||||
void WriteU8(long addr, uint value, string domain = null);
|
||||
void WriteU16(long addr, uint value, string domain = null);
|
||||
void WriteU24(long addr, uint value, string domain = null);
|
||||
void WriteU32(long addr, uint value, string domain = null);
|
||||
#endregion
|
||||
#endregion
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
using System;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface IMemEvents : IExternalApi
|
||||
{
|
||||
void AddReadCallback(Action cb, uint address, string domain);
|
||||
void AddWriteCallback(Action cb, uint address, string domain);
|
||||
void AddExecCallback(Action cb, uint address, string domain);
|
||||
void RemoveMemoryCallback(Action cb);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface IMemorySaveState : IExternalApi
|
||||
{
|
||||
string SaveCoreStateToMemory();
|
||||
void LoadCoreStateFromMemory(string identifier);
|
||||
void DeleteState(string identifier);
|
||||
void ClearInMemoryStates();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
using System.Collections.Generic;
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface IMovie : IExternalApi
|
||||
{
|
||||
bool StartsFromSavestate();
|
||||
bool StartsFromSaveram();
|
||||
string Filename();
|
||||
Dictionary<string, dynamic> GetInput(int frame);
|
||||
string GetInputAsMnemonic(int frame);
|
||||
bool GetReadOnly();
|
||||
ulong GetRerecordCount();
|
||||
bool GetRerecordCounting();
|
||||
bool IsLoaded();
|
||||
double Length();
|
||||
string Mode();
|
||||
void Save(string filename = "");
|
||||
void SetReadOnly(bool readOnly);
|
||||
void SetRerecordCount(double count);
|
||||
void SetRerecordCounting(bool counting);
|
||||
void Stop();
|
||||
double GetFps();
|
||||
Dictionary<string, string> GetHeader();
|
||||
List<string> GetComments();
|
||||
List<string> GetSubtitles();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface ISaveState : IExternalApi
|
||||
{
|
||||
void Load(string path);
|
||||
void LoadSlot(int slotNum);
|
||||
void Save(string path);
|
||||
void SaveSlot(int slotNum);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface ISql : IExternalApi
|
||||
{
|
||||
string CreateDatabase(string name);
|
||||
string OpenDatabase(string name);
|
||||
string WriteCommand(string query = "");
|
||||
dynamic ReadCommand(string query = "");
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
using System;
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface ITool : IExternalApi
|
||||
{
|
||||
Type GetTool(string name);
|
||||
object CreateInstance(string name);
|
||||
void OpenCheats();
|
||||
void OpenHexEditor();
|
||||
void OpenRamWatch();
|
||||
void OpenRamSearch();
|
||||
void OpenTasStudio();
|
||||
void OpenToolBox();
|
||||
void OpenTraceLogger();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
public interface IUserData : IExternalApi
|
||||
{
|
||||
void Set(string name, object value);
|
||||
object Get(string key);
|
||||
void Clear();
|
||||
bool Remove(string key);
|
||||
bool ContainsKey(string key);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface defines the mechanism by which External tools can retrieve <seealso cref="IExternalApi" />
|
||||
/// from a client implementation
|
||||
/// An implementation should collect all available IExternalApi instances.
|
||||
/// This interface defines only the external interaction. This interface does not specify the means
|
||||
/// by which a api provider will be populated with available apis. However, an implementation
|
||||
/// by design must provide this mechanism
|
||||
/// </summary>
|
||||
/// <seealso cref="IExternalApi"/>
|
||||
public interface IExternalApiProvider
|
||||
{
|
||||
/// <summary>e
|
||||
/// Returns whether or not T is available
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The <seealso cref="IExternalApi" /> to check</typeparam>
|
||||
bool HasApi<T>() where T : IExternalApi;
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether or not t is available
|
||||
/// </summary>
|
||||
bool HasApi(Type t);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of T if T is available
|
||||
/// Else returns null
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The requested <seealso cref="IExternalApi" /></typeparam>
|
||||
T GetApi<T>() where T : IExternalApi;
|
||||
|
||||
/// <summary>
|
||||
/// Returns an instance of t if t is available
|
||||
/// Else returns null
|
||||
/// </summary>
|
||||
object GetApi(Type t);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of all currently registered Apis available to be retrieved
|
||||
/// </summary>
|
||||
IEnumerable<Type> AvailableApis { get; }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
namespace BizHawk.Client.ApiHawk
|
||||
{
|
||||
interface IPlugin
|
||||
{
|
||||
void PreFrameCallback();
|
||||
void PostFrameCallback();
|
||||
void SaveStateCallback(string name);
|
||||
void LoadStateCallback(string name);
|
||||
void InputPollCallback();
|
||||
void Init(IApiContainer api);
|
||||
}
|
||||
}
|
|
@ -64,6 +64,7 @@
|
|||
</Reference>
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.IO.Compression" />
|
||||
<Reference Include="System.Windows.Forms" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
|
@ -244,6 +245,7 @@
|
|||
<Compile Include="movie\tasproj\TasMovieRecord.cs" />
|
||||
<Compile Include="movie\tasproj\TasStateManagerSettings.cs" />
|
||||
<Compile Include="NESGameGenieEncoderDecoder.cs" />
|
||||
<Compile Include="OpenAdvanced.cs" />
|
||||
<Compile Include="PathManager.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="QuickBmpFile.cs" />
|
||||
|
|
|
@ -10,7 +10,7 @@ using Newtonsoft.Json;
|
|||
//this file contains some cumbersome self-"serialization" in order to gain a modicum of control over what the serialized output looks like
|
||||
//I don't want them to look like crufty json
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
public interface IOpenAdvanced
|
||||
{
|
||||
|
@ -74,7 +74,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
class OpenAdvanced_Libretro : IOpenAdvanced, IOpenAdvancedLibretro
|
||||
public class OpenAdvanced_Libretro : IOpenAdvanced, IOpenAdvancedLibretro
|
||||
{
|
||||
public OpenAdvanced_Libretro()
|
||||
{
|
||||
|
@ -103,7 +103,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
public string CorePath { get { return token.CorePath; } set { token.CorePath = value; } }
|
||||
}
|
||||
|
||||
class OpenAdvanced_LibretroNoGame : IOpenAdvanced, IOpenAdvancedLibretro
|
||||
public class OpenAdvanced_LibretroNoGame : IOpenAdvanced, IOpenAdvancedLibretro
|
||||
{
|
||||
//you might think ideally we'd fetch the libretro core name from the core info inside it
|
||||
//but that would involve spinning up excess libretro core instances, which probably isnt good for stability, no matter how much we wish otherwise, not to mention slow.
|
||||
|
@ -140,7 +140,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
public string CorePath { get { return _corePath; } set { _corePath = value; } }
|
||||
}
|
||||
|
||||
class OpenAdvanced_OpenRom : IOpenAdvanced
|
||||
public class OpenAdvanced_OpenRom : IOpenAdvanced
|
||||
{
|
||||
public OpenAdvanced_OpenRom()
|
||||
{}
|
|
@ -1,9 +1,8 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data.SQLite;
|
||||
using NLua;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace BizHawk.Client.Common
|
||||
{
|
||||
|
|
|
@ -217,9 +217,9 @@ namespace BizHawk.Client.Common
|
|||
case DisplayType.Hex:
|
||||
return val.ToHexString(8);
|
||||
case DisplayType.FixedPoint_20_12:
|
||||
return $"{val / 4096.0:0.######}";
|
||||
return $"{(int)val / 4096.0:0.######}";
|
||||
case DisplayType.FixedPoint_16_16:
|
||||
return $"{val / 65536.0:0.######}";
|
||||
return $"{(int)val / 65536.0:0.######}";
|
||||
case DisplayType.Float:
|
||||
var bytes = BitConverter.GetBytes(val);
|
||||
var _float = BitConverter.ToSingle(bytes, 0);
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Client.ApiHawk;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public sealed class ApiContainer : IApiContainer
|
||||
{
|
||||
public IComm Comm => (IComm)Libraries[typeof(CommApi)];
|
||||
public IEmu Emu => (IEmu)Libraries[typeof(EmuApi)];
|
||||
public IGameInfo GameInfo => (IGameInfo)Libraries[typeof(GameInfoApi)];
|
||||
public IGui Gui => (IGui)Libraries[typeof(GuiApi)];
|
||||
public IInput Input => (IInput)Libraries[typeof(InputApi)];
|
||||
public IJoypad Joypad => (IJoypad)Libraries[typeof(JoypadApi)];
|
||||
public IMem Mem => (IMem)Libraries[typeof(MemApi)];
|
||||
public IMemEvents MemEvents => (IMemEvents)Libraries[typeof(MemEventsApi)];
|
||||
public IMemorySaveState MemorySaveState => (IMemorySaveState)Libraries[typeof(MemorySaveStateApi)];
|
||||
public IMovie Movie => (IMovie)Libraries[typeof(MovieApi)];
|
||||
public ISaveState SaveState => (ISaveState)Libraries[typeof(SaveStateApi)];
|
||||
public ISql Sql => (ISql)Libraries[typeof(SqlApi)];
|
||||
public ITool Tool => (ITool)Libraries[typeof(ToolApi)];
|
||||
public IUserData UserData => (IUserData)Libraries[typeof(UserDataApi)];
|
||||
public Dictionary<Type, IExternalApi> Libraries { get; set; }
|
||||
public ApiContainer(Dictionary<Type, IExternalApi> libs)
|
||||
{
|
||||
Libraries = libs;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
using BizHawk.Common.ReflectionExtensions;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Client.ApiHawk;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
|
||||
{
|
||||
public static class ApiManager
|
||||
{
|
||||
private static ApiContainer container;
|
||||
private static void Register(IEmulatorServiceProvider serviceProvider)
|
||||
{
|
||||
// Register external apis
|
||||
var apis = Assembly
|
||||
.Load("BizHawk.Client.ApiHawk")
|
||||
.GetTypes()
|
||||
.Where(t => typeof(IExternalApi).IsAssignableFrom(t))
|
||||
.Where(t => t.IsSealed)
|
||||
.Where(t => ServiceInjector.IsAvailable(serviceProvider, t))
|
||||
.ToList();
|
||||
|
||||
apis.AddRange(
|
||||
Assembly
|
||||
.GetAssembly(typeof(ApiContainer))
|
||||
.GetTypes()
|
||||
.Where(t => typeof(IExternalApi).IsAssignableFrom(t))
|
||||
.Where(t => t.IsSealed)
|
||||
.Where(t => ServiceInjector.IsAvailable(serviceProvider, t)));
|
||||
|
||||
foreach (var api in apis)
|
||||
{
|
||||
var instance = (IExternalApi)Activator.CreateInstance(api);
|
||||
ServiceInjector.UpdateServices(serviceProvider, instance);
|
||||
Libraries.Add(api, instance);
|
||||
}
|
||||
container = new ApiContainer(Libraries);
|
||||
GlobalWin.ApiProvider = new BasicApiProvider(container);
|
||||
}
|
||||
private static readonly Dictionary<Type, IExternalApi> Libraries = new Dictionary<Type, IExternalApi>();
|
||||
public static void Restart(IEmulatorServiceProvider newServiceProvider)
|
||||
{
|
||||
Libraries.Clear();
|
||||
Register(newServiceProvider);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Client.ApiHawk;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Windows.Forms;
|
||||
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public sealed class CommApi : IComm
|
||||
{
|
||||
[RequiredService]
|
||||
private IEmulator Emulator { get; set; }
|
||||
|
||||
[RequiredService]
|
||||
private IVideoProvider VideoProvider { get; set; }
|
||||
|
||||
public CommApi() : base()
|
||||
{ }
|
||||
|
||||
public string SocketServerScreenShot()
|
||||
{
|
||||
return GlobalWin.socketServer.SendScreenshot();
|
||||
}
|
||||
public string SocketServerScreenShotResponse()
|
||||
{
|
||||
return GlobalWin.socketServer.SendScreenshot(1000).ToString();
|
||||
}
|
||||
|
||||
public string SocketServerSend(string SendString)
|
||||
{
|
||||
return "Sent : " + GlobalWin.socketServer.SendString(SendString).ToString() + " bytes";
|
||||
}
|
||||
public string SocketServerResponse()
|
||||
{
|
||||
return GlobalWin.socketServer.ReceiveMessage();
|
||||
}
|
||||
|
||||
public bool SocketServerSuccessful()
|
||||
{
|
||||
return GlobalWin.socketServer.Successful();
|
||||
}
|
||||
public void SocketServerSetTimeout(int timeout)
|
||||
{
|
||||
GlobalWin.socketServer.SetTimeout(timeout);
|
||||
}
|
||||
// All MemoryMappedFile related methods
|
||||
public void MmfSetFilename(string filename)
|
||||
{
|
||||
GlobalWin.memoryMappedFiles.SetFilename(filename);
|
||||
}
|
||||
public string MmfSetFilename()
|
||||
{
|
||||
return GlobalWin.memoryMappedFiles.GetFilename();
|
||||
}
|
||||
|
||||
public int MmfScreenshot()
|
||||
{
|
||||
return GlobalWin.memoryMappedFiles.ScreenShotToFile();
|
||||
}
|
||||
|
||||
public int MmfWrite(string mmf_filename, string outputString)
|
||||
{
|
||||
return GlobalWin.memoryMappedFiles.WriteToFile(mmf_filename, Encoding.ASCII.GetBytes(outputString));
|
||||
}
|
||||
public string MmfRead(string mmf_filename, int expectedSize)
|
||||
{
|
||||
return GlobalWin.memoryMappedFiles.ReadFromFile(mmf_filename, expectedSize).ToString();
|
||||
}
|
||||
// All HTTP related methods
|
||||
public string HttpTest()
|
||||
{
|
||||
var list = new StringBuilder();
|
||||
list.AppendLine(GlobalWin.httpCommunication.TestGet());
|
||||
list.AppendLine(GlobalWin.httpCommunication.SendScreenshot());
|
||||
list.AppendLine("done testing");
|
||||
return list.ToString();
|
||||
}
|
||||
public string HttpTestGet()
|
||||
{
|
||||
return GlobalWin.httpCommunication.TestGet();
|
||||
}
|
||||
public string HttpGet(string url)
|
||||
{
|
||||
return GlobalWin.httpCommunication.ExecGet(url);
|
||||
}
|
||||
|
||||
public string HttpPost(string url, string payload)
|
||||
{
|
||||
return GlobalWin.httpCommunication.ExecPost(url, payload);
|
||||
}
|
||||
public string HttpPostScreenshot()
|
||||
{
|
||||
return GlobalWin.httpCommunication.SendScreenshot();
|
||||
}
|
||||
public void HttpSetTimeout(int timeout)
|
||||
{
|
||||
GlobalWin.httpCommunication.SetTimeout(timeout);
|
||||
}
|
||||
public void HttpSetPostUrl(string url)
|
||||
{
|
||||
GlobalWin.httpCommunication.SetPostUrl(url);
|
||||
}
|
||||
public void HttpSetGetUrl(string url)
|
||||
{
|
||||
GlobalWin.httpCommunication.SetGetUrl(url);
|
||||
}
|
||||
public string HttpGetPostUrl()
|
||||
{
|
||||
return GlobalWin.httpCommunication.GetPostUrl();
|
||||
}
|
||||
public string HttpGetGetUrl()
|
||||
{
|
||||
return GlobalWin.httpCommunication.GetGetUrl();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,655 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Windows.Forms;
|
||||
using System.IO;
|
||||
|
||||
using BizHawk.Client.ApiHawk;
|
||||
using BizHawk.Emulation.Common;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public sealed class GuiApi : IGui
|
||||
{
|
||||
[RequiredService]
|
||||
private IEmulator Emulator { get; set; }
|
||||
private Color _defaultForeground = Color.White;
|
||||
private Color? _defaultBackground;
|
||||
private Color? _defaultTextBackground = Color.FromArgb(128, 0, 0, 0);
|
||||
private int _defaultPixelFont = 1; // gens
|
||||
private Padding _padding = new Padding(0);
|
||||
private ImageAttributes _attributes = new ImageAttributes();
|
||||
private System.Drawing.Drawing2D.CompositingMode _compositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
|
||||
|
||||
|
||||
public GuiApi()
|
||||
{ }
|
||||
|
||||
private DisplaySurface _GUISurface = null;
|
||||
|
||||
public bool HasGUISurface => _GUISurface != null;
|
||||
|
||||
#region Gui API
|
||||
public void ToggleCompositingMode()
|
||||
{
|
||||
_compositingMode = 1 - _compositingMode;
|
||||
}
|
||||
|
||||
public ImageAttributes GetAttributes()
|
||||
{
|
||||
return _attributes;
|
||||
}
|
||||
public void SetAttributes(ImageAttributes a)
|
||||
{
|
||||
_attributes = a;
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var brush in _solidBrushes.Values)
|
||||
{
|
||||
brush.Dispose();
|
||||
}
|
||||
|
||||
foreach (var brush in _pens.Values)
|
||||
{
|
||||
brush.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawNew(string name, bool? clear = true)
|
||||
{
|
||||
try
|
||||
{
|
||||
DrawFinish();
|
||||
_GUISurface = GlobalWin.DisplayManager.LockLuaSurface(name, clear ?? true);
|
||||
}
|
||||
catch (InvalidOperationException ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawFinish()
|
||||
{
|
||||
if (_GUISurface != null)
|
||||
{
|
||||
GlobalWin.DisplayManager.UnlockLuaSurface(_GUISurface);
|
||||
}
|
||||
|
||||
_GUISurface = null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Helpers
|
||||
private readonly Dictionary<string, Image> _imageCache = new Dictionary<string, Image>();
|
||||
private readonly Dictionary<Color, SolidBrush> _solidBrushes = new Dictionary<Color, SolidBrush>();
|
||||
private readonly Dictionary<Color, Pen> _pens = new Dictionary<Color, Pen>();
|
||||
private SolidBrush GetBrush(Color color)
|
||||
{
|
||||
SolidBrush b;
|
||||
if (!_solidBrushes.TryGetValue(color, out b))
|
||||
{
|
||||
b = new SolidBrush(color);
|
||||
_solidBrushes[color] = b;
|
||||
}
|
||||
|
||||
return b;
|
||||
}
|
||||
|
||||
private Pen GetPen(Color color)
|
||||
{
|
||||
Pen p;
|
||||
if (!_pens.TryGetValue(color, out p))
|
||||
{
|
||||
p = new Pen(color);
|
||||
_pens[color] = p;
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
private Graphics GetGraphics()
|
||||
{
|
||||
var g = _GUISurface == null ? Graphics.FromImage(new Bitmap(1,1)) : _GUISurface.GetGraphics();
|
||||
|
||||
// we don't like CoreComm, right? Someone should find a different way to do this then.
|
||||
var tx = Emulator.CoreComm.ScreenLogicalOffsetX;
|
||||
var ty = Emulator.CoreComm.ScreenLogicalOffsetY;
|
||||
if (tx != 0 || ty != 0)
|
||||
{
|
||||
var transform = g.Transform;
|
||||
transform.Translate(-tx, -ty);
|
||||
g.Transform = transform;
|
||||
}
|
||||
|
||||
return g;
|
||||
}
|
||||
public void SetPadding(int all)
|
||||
{
|
||||
_padding = new Padding(all);
|
||||
}
|
||||
public void SetPadding(int x, int y)
|
||||
{
|
||||
_padding = new Padding(x / 2, y / 2, x / 2 + x & 1, y / 2 + y & 1);
|
||||
}
|
||||
public void SetPadding(int l, int t, int r, int b)
|
||||
{
|
||||
_padding = new Padding(l, t, r, b);
|
||||
}
|
||||
public Padding GetPadding()
|
||||
{
|
||||
return _padding;
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void AddMessage(string message)
|
||||
{
|
||||
GlobalWin.OSD.AddMessage(message);
|
||||
}
|
||||
|
||||
public void ClearGraphics()
|
||||
{
|
||||
_GUISurface.Clear();
|
||||
DrawFinish();
|
||||
}
|
||||
|
||||
public void ClearText()
|
||||
{
|
||||
GlobalWin.OSD.ClearGUIText();
|
||||
}
|
||||
|
||||
public void SetDefaultForegroundColor(Color color)
|
||||
{
|
||||
_defaultForeground = color;
|
||||
}
|
||||
|
||||
public void SetDefaultBackgroundColor(Color color)
|
||||
{
|
||||
_defaultBackground = color;
|
||||
}
|
||||
|
||||
public void SetDefaultTextBackground(Color color)
|
||||
{
|
||||
_defaultTextBackground = color;
|
||||
}
|
||||
|
||||
public void SetDefaultPixelFont(string fontfamily)
|
||||
{
|
||||
switch (fontfamily)
|
||||
{
|
||||
case "fceux":
|
||||
case "0":
|
||||
_defaultPixelFont = 0;
|
||||
break;
|
||||
case "gens":
|
||||
case "1":
|
||||
_defaultPixelFont = 1;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"Unable to find font family: {fontfamily}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawBezier(Point p1, Point p2, Point p3, Point p4, Color? color = null)
|
||||
{
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
try
|
||||
{
|
||||
g.CompositingMode = _compositingMode;
|
||||
g.DrawBezier(GetPen(color ?? _defaultForeground), p1, p2, p3, p4);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawBeziers(Point[] points, Color? color = null)
|
||||
{
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
try
|
||||
{
|
||||
g.CompositingMode = _compositingMode;
|
||||
g.DrawBeziers(GetPen(color ?? _defaultForeground), points);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
public void DrawBox(int x, int y, int x2, int y2, Color? line = null, Color? background = null)
|
||||
{
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
try
|
||||
{
|
||||
float w;
|
||||
float h;
|
||||
if (x < x2)
|
||||
{
|
||||
w = x2 - x;
|
||||
}
|
||||
else
|
||||
{
|
||||
x2 = x - x2;
|
||||
x -= x2;
|
||||
w = Math.Max(x2, 0.1f);
|
||||
}
|
||||
|
||||
if (y < y2)
|
||||
{
|
||||
h = y2 - y;
|
||||
}
|
||||
else
|
||||
{
|
||||
y2 = y - y2;
|
||||
y -= y2;
|
||||
h = Math.Max(y2, 0.1f);
|
||||
}
|
||||
|
||||
g.CompositingMode = _compositingMode;
|
||||
g.DrawRectangle(GetPen(line ?? _defaultForeground), x, y, w, h);
|
||||
|
||||
var bg = background ?? _defaultBackground;
|
||||
if (bg.HasValue)
|
||||
{
|
||||
g.FillRectangle(GetBrush(bg.Value), x + 1, y + 1, Math.Max(w - 1, 0), Math.Max(h - 1, 0));
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// need to stop the script from here
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawEllipse(int x, int y, int width, int height, Color? line = null, Color? background = null)
|
||||
{
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
try
|
||||
{
|
||||
var bg = background ?? _defaultBackground;
|
||||
if (bg.HasValue)
|
||||
{
|
||||
var brush = GetBrush(bg.Value);
|
||||
g.FillEllipse(brush, x, y, width, height);
|
||||
}
|
||||
|
||||
g.CompositingMode = _compositingMode;
|
||||
g.DrawEllipse(GetPen(line ?? _defaultForeground), x, y, width, height);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
// need to stop the script from here
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawIcon(string path, int x, int y, int? width = null, int? height = null)
|
||||
{
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
AddMessage("File not found: " + path);
|
||||
return;
|
||||
}
|
||||
|
||||
Icon icon;
|
||||
if (width.HasValue && height.HasValue)
|
||||
{
|
||||
icon = new Icon(path, width.Value, height.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
icon = new Icon(path);
|
||||
}
|
||||
|
||||
g.CompositingMode = _compositingMode;
|
||||
g.DrawIcon(icon, x, y);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawImage(string path, int x, int y, int? width = null, int? height = null, bool cache = true)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
Console.WriteLine("File not found: " + path);
|
||||
return;
|
||||
}
|
||||
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
Image img;
|
||||
if (_imageCache.ContainsKey(path))
|
||||
{
|
||||
img = _imageCache[path];
|
||||
}
|
||||
else
|
||||
{
|
||||
img = Image.FromFile(path);
|
||||
if (cache)
|
||||
{
|
||||
_imageCache.Add(path, img);
|
||||
}
|
||||
}
|
||||
var destRect = new Rectangle(x, y, width ?? img.Width, height ?? img.Height);
|
||||
|
||||
g.CompositingMode = _compositingMode;
|
||||
g.DrawImage(img, destRect, 0, 0, img.Width, img.Height, GraphicsUnit.Pixel, _attributes);
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearImageCache()
|
||||
{
|
||||
foreach (var image in _imageCache)
|
||||
{
|
||||
image.Value.Dispose();
|
||||
}
|
||||
|
||||
_imageCache.Clear();
|
||||
}
|
||||
|
||||
public void DrawImageRegion(string path, int source_x, int source_y, int source_width, int source_height, int dest_x, int dest_y, int? dest_width = null, int? dest_height = null)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
Console.WriteLine("File not found: " + path);
|
||||
return;
|
||||
}
|
||||
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
Image img;
|
||||
if (_imageCache.ContainsKey(path))
|
||||
{
|
||||
img = _imageCache[path];
|
||||
}
|
||||
else
|
||||
{
|
||||
img = Image.FromFile(path);
|
||||
_imageCache.Add(path, img);
|
||||
}
|
||||
|
||||
var destRect = new Rectangle(dest_x, dest_y, dest_width ?? source_width, dest_height ?? source_height);
|
||||
|
||||
g.CompositingMode = _compositingMode;
|
||||
g.DrawImage(img, destRect, source_x, source_y, source_width, source_height, GraphicsUnit.Pixel, _attributes);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawLine(int x1, int y1, int x2, int y2, Color? color = null)
|
||||
{
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
g.CompositingMode = _compositingMode;
|
||||
g.DrawLine(GetPen(color ?? _defaultForeground), x1, y1, x2, y2);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawAxis(int x, int y, int size, Color? color = null)
|
||||
{
|
||||
DrawLine(x + size, y, x - size, y, color ?? _defaultForeground);
|
||||
DrawLine(x, y + size, x, y - size, color ?? _defaultForeground);
|
||||
}
|
||||
|
||||
public void DrawPie(int x, int y, int width, int height, int startangle, int sweepangle, Color? line = null, Color? background = null)
|
||||
{
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
g.CompositingMode = _compositingMode;
|
||||
var bg = background ?? _defaultBackground;
|
||||
if (bg.HasValue)
|
||||
{
|
||||
var brush = GetBrush(bg.Value);
|
||||
g.FillPie(brush, x, y, width, height, startangle, sweepangle);
|
||||
}
|
||||
|
||||
g.DrawPie(GetPen(line ?? _defaultForeground), x + 1, y + 1, width - 1, height - 1, startangle, sweepangle);
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawPixel(int x, int y, Color? color = null)
|
||||
{
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
try
|
||||
{
|
||||
g.DrawLine(GetPen(color ?? _defaultForeground), x, y, x + 0.1F, y);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawPolygon(Point[] points, Color? line = null, Color? background = null)
|
||||
{
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
try
|
||||
{
|
||||
g.DrawPolygon(GetPen(line ?? _defaultForeground), points);
|
||||
var bg = background ?? _defaultBackground;
|
||||
if (bg.HasValue)
|
||||
{
|
||||
g.FillPolygon(GetBrush(bg.Value), points);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawRectangle(int x, int y, int width, int height, Color? line = null, Color? background = null)
|
||||
{
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
var w = Math.Max(width, 0.1F);
|
||||
var h = Math.Max(height, 0.1F);
|
||||
g.DrawRectangle(GetPen(line ?? _defaultForeground), x, y, w, h);
|
||||
var bg = background ?? _defaultBackground;
|
||||
if (bg.HasValue)
|
||||
{
|
||||
g.FillRectangle(GetBrush(bg.Value), x + 1, y + 1, Math.Max(w - 1, 0), Math.Max(h - 1, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawString(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, int? fontsize = null,
|
||||
string fontfamily = null, string fontstyle = null, string horizalign = null, string vertalign = null)
|
||||
{
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
try
|
||||
{
|
||||
var family = FontFamily.GenericMonospace;
|
||||
if (fontfamily != null)
|
||||
{
|
||||
family = new FontFamily(fontfamily);
|
||||
}
|
||||
|
||||
var fstyle = FontStyle.Regular;
|
||||
if (fontstyle != null)
|
||||
{
|
||||
switch (fontstyle.ToLower())
|
||||
{
|
||||
default:
|
||||
case "regular":
|
||||
break;
|
||||
case "bold":
|
||||
fstyle = FontStyle.Bold;
|
||||
break;
|
||||
case "italic":
|
||||
fstyle = FontStyle.Italic;
|
||||
break;
|
||||
case "strikethrough":
|
||||
fstyle = FontStyle.Strikeout;
|
||||
break;
|
||||
case "underline":
|
||||
fstyle = FontStyle.Underline;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// The text isn't written out using GenericTypographic, so measuring it using GenericTypographic seemed to make it worse.
|
||||
// And writing it out with GenericTypographic just made it uglier. :p
|
||||
var f = new StringFormat(StringFormat.GenericDefault);
|
||||
var font = new Font(family, fontsize ?? 12, fstyle, GraphicsUnit.Pixel);
|
||||
Size sizeOfText = g.MeasureString(message, font, 0, f).ToSize();
|
||||
if (horizalign != null)
|
||||
{
|
||||
switch (horizalign.ToLower())
|
||||
{
|
||||
default:
|
||||
case "left":
|
||||
break;
|
||||
case "center":
|
||||
x -= sizeOfText.Width / 2;
|
||||
break;
|
||||
case "right":
|
||||
x -= sizeOfText.Width;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (vertalign != null)
|
||||
{
|
||||
switch (vertalign.ToLower())
|
||||
{
|
||||
default:
|
||||
case "bottom":
|
||||
break;
|
||||
case "middle":
|
||||
y -= sizeOfText.Height / 2;
|
||||
break;
|
||||
case "top":
|
||||
y -= sizeOfText.Height;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var bg = backcolor ?? _defaultBackground;
|
||||
if (bg.HasValue)
|
||||
{
|
||||
for (var xd = -1; xd <= 1; xd++)
|
||||
{
|
||||
for (var yd = -1; yd <= 1; yd++)
|
||||
{
|
||||
g.DrawString(message, font, GetBrush(bg.Value), x + xd, y + yd);
|
||||
}
|
||||
}
|
||||
}
|
||||
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
|
||||
g.DrawString(message, font, GetBrush(forecolor ?? _defaultForeground), x, y);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void DrawText(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, string fontfamily = null)
|
||||
{
|
||||
using (var g = GetGraphics())
|
||||
{
|
||||
try
|
||||
{
|
||||
var index = 0;
|
||||
if (string.IsNullOrEmpty(fontfamily))
|
||||
{
|
||||
index = _defaultPixelFont;
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (fontfamily)
|
||||
{
|
||||
case "fceux":
|
||||
case "0":
|
||||
index = 0;
|
||||
break;
|
||||
case "gens":
|
||||
case "1":
|
||||
index = 1;
|
||||
break;
|
||||
default:
|
||||
Console.WriteLine($"Unable to find font family: {fontfamily}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
var f = new StringFormat(StringFormat.GenericTypographic)
|
||||
{
|
||||
FormatFlags = StringFormatFlags.MeasureTrailingSpaces
|
||||
};
|
||||
var font = new Font(GlobalWin.DisplayManager.CustomFonts.Families[index], 8, FontStyle.Regular, GraphicsUnit.Pixel);
|
||||
Size sizeOfText = g.MeasureString(message, font, 0, f).ToSize();
|
||||
var rect = new Rectangle(new Point(x, y), sizeOfText + new Size(1, 0));
|
||||
if (backcolor.HasValue) g.FillRectangle(GetBrush(backcolor.Value), rect);
|
||||
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
|
||||
g.DrawString(message, font, GetBrush(forecolor ?? _defaultForeground), x, y);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Text(int x, int y, string message, Color? forecolor = null, string anchor = null)
|
||||
{
|
||||
var a = 0;
|
||||
|
||||
if (!string.IsNullOrEmpty(anchor))
|
||||
{
|
||||
switch (anchor)
|
||||
{
|
||||
case "0":
|
||||
case "topleft":
|
||||
a = 0;
|
||||
break;
|
||||
case "1":
|
||||
case "topright":
|
||||
a = 1;
|
||||
break;
|
||||
case "2":
|
||||
case "bottomleft":
|
||||
a = 2;
|
||||
break;
|
||||
case "3":
|
||||
case "bottomright":
|
||||
a = 3;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
x -= Emulator.CoreComm.ScreenLogicalOffsetX;
|
||||
y -= Emulator.CoreComm.ScreenLogicalOffsetY;
|
||||
}
|
||||
|
||||
GlobalWin.OSD.AddGUIText(message, x, y, Color.Black, forecolor ?? Color.White, a);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Client.ApiHawk;
|
||||
using BizHawk.Client.Common;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public sealed class InputApi : IInput
|
||||
{
|
||||
public InputApi() : base()
|
||||
{ }
|
||||
|
||||
public Dictionary<string,bool> Get()
|
||||
{
|
||||
var buttons = new Dictionary<string, bool>();
|
||||
foreach (var kvp in Global.ControllerInputCoalescer.BoolButtons().Where(kvp => kvp.Value))
|
||||
{
|
||||
buttons[kvp.Key] = true;
|
||||
}
|
||||
|
||||
return buttons;
|
||||
}
|
||||
|
||||
public Dictionary<string, dynamic> GetMouse()
|
||||
{
|
||||
var buttons = new Dictionary<string, dynamic>();
|
||||
|
||||
// TODO - need to specify whether in "emu" or "native" coordinate space.
|
||||
var p = GlobalWin.DisplayManager.UntransformPoint(Control.MousePosition);
|
||||
buttons["X"] = p.X;
|
||||
buttons["Y"] = p.Y;
|
||||
buttons[MouseButtons.Left.ToString()] = (Control.MouseButtons & MouseButtons.Left) != 0;
|
||||
buttons[MouseButtons.Middle.ToString()] = (Control.MouseButtons & MouseButtons.Middle) != 0;
|
||||
buttons[MouseButtons.Right.ToString()] = (Control.MouseButtons & MouseButtons.Right) != 0;
|
||||
buttons[MouseButtons.XButton1.ToString()] = (Control.MouseButtons & MouseButtons.XButton1) != 0;
|
||||
buttons[MouseButtons.XButton2.ToString()] = (Control.MouseButtons & MouseButtons.XButton2) != 0;
|
||||
buttons["Wheel"] = GlobalWin.MainForm.MouseWheelTracker;
|
||||
return buttons;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
using BizHawk.Client.ApiHawk;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public sealed class SaveStateApi : ISaveState
|
||||
{
|
||||
public SaveStateApi() : base()
|
||||
{ }
|
||||
|
||||
public void Load(string path)
|
||||
{
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
Console.WriteLine($"could not find file: {path}");
|
||||
}
|
||||
else
|
||||
{
|
||||
GlobalWin.MainForm.LoadState(path, Path.GetFileName(path), true);
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadSlot(int slotNum)
|
||||
{
|
||||
if (slotNum >= 0 && slotNum <= 9)
|
||||
{
|
||||
GlobalWin.MainForm.LoadQuickSave("QuickSave" + slotNum, true);
|
||||
}
|
||||
}
|
||||
|
||||
public void Save(string path)
|
||||
{
|
||||
GlobalWin.MainForm.SaveState(path, path, true);
|
||||
}
|
||||
|
||||
public void SaveSlot(int slotNum)
|
||||
{
|
||||
if (slotNum >= 0 && slotNum <= 9)
|
||||
{
|
||||
GlobalWin.MainForm.SaveQuickSave("QuickSave" + slotNum);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,162 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using BizHawk.Common;
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Client.ApiHawk;
|
||||
using BizHawk.Client.Common;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
public sealed class ToolApi : ITool
|
||||
{
|
||||
private class ToolStatic
|
||||
{
|
||||
public Type GetTool(string name)
|
||||
{
|
||||
var toolType = ReflectionUtil.GetTypeByName(name)
|
||||
.FirstOrDefault(x => typeof(IToolForm).IsAssignableFrom(x) && !x.IsInterface);
|
||||
|
||||
if (toolType != null)
|
||||
{
|
||||
GlobalWin.Tools.Load(toolType);
|
||||
}
|
||||
|
||||
var selectedTool = GlobalWin.Tools.AvailableTools
|
||||
.FirstOrDefault(tool => tool.GetType().Name.ToLower() == name.ToLower());
|
||||
|
||||
if (selectedTool != null)
|
||||
{
|
||||
return selectedTool;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public object CreateInstance(string name)
|
||||
{
|
||||
var possibleTypes = ReflectionUtil.GetTypeByName(name);
|
||||
|
||||
if (possibleTypes.Any())
|
||||
{
|
||||
return Activator.CreateInstance(possibleTypes.First());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void OpenCheats()
|
||||
{
|
||||
GlobalWin.Tools.Load<Cheats>();
|
||||
}
|
||||
|
||||
public static void OpenHexEditor()
|
||||
{
|
||||
GlobalWin.Tools.Load<HexEditor>();
|
||||
}
|
||||
|
||||
public static void OpenRamWatch()
|
||||
{
|
||||
GlobalWin.Tools.LoadRamWatch(loadDialog: true);
|
||||
}
|
||||
|
||||
public static void OpenRamSearch()
|
||||
{
|
||||
GlobalWin.Tools.Load<RamSearch>();
|
||||
}
|
||||
|
||||
public static void OpenTasStudio()
|
||||
{
|
||||
GlobalWin.Tools.Load<TAStudio>();
|
||||
}
|
||||
|
||||
public static void OpenToolBox()
|
||||
{
|
||||
GlobalWin.Tools.Load<ToolBox>();
|
||||
}
|
||||
|
||||
public static void OpenTraceLogger()
|
||||
{
|
||||
GlobalWin.Tools.Load<TraceLogger>();
|
||||
}
|
||||
|
||||
}
|
||||
[RequiredService]
|
||||
private static IEmulator Emulator { get; set; }
|
||||
|
||||
[RequiredService]
|
||||
private static IVideoProvider VideoProvider { get; set; }
|
||||
|
||||
public ToolApi()
|
||||
{ }
|
||||
|
||||
public Type GetTool(string name)
|
||||
{
|
||||
var toolType = ReflectionUtil.GetTypeByName(name)
|
||||
.FirstOrDefault(x => typeof(IToolForm).IsAssignableFrom(x) && !x.IsInterface);
|
||||
|
||||
if (toolType != null)
|
||||
{
|
||||
GlobalWin.Tools.Load(toolType);
|
||||
}
|
||||
|
||||
var selectedTool = GlobalWin.Tools.AvailableTools
|
||||
.FirstOrDefault(tool => tool.GetType().Name.ToLower() == name.ToLower());
|
||||
|
||||
if (selectedTool != null)
|
||||
{
|
||||
return selectedTool;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public object CreateInstance(string name)
|
||||
{
|
||||
var possibleTypes = ReflectionUtil.GetTypeByName(name);
|
||||
|
||||
if (possibleTypes.Any())
|
||||
{
|
||||
return Activator.CreateInstance(possibleTypes.First());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void OpenCheats()
|
||||
{
|
||||
ToolStatic.OpenCheats();
|
||||
}
|
||||
|
||||
public void OpenHexEditor()
|
||||
{
|
||||
ToolStatic.OpenHexEditor();
|
||||
}
|
||||
|
||||
public void OpenRamWatch()
|
||||
{
|
||||
ToolStatic.OpenRamWatch();
|
||||
}
|
||||
|
||||
public void OpenRamSearch()
|
||||
{
|
||||
ToolStatic.OpenRamSearch();
|
||||
}
|
||||
|
||||
public void OpenTasStudio()
|
||||
{
|
||||
ToolStatic.OpenTasStudio();
|
||||
}
|
||||
|
||||
public void OpenToolBox()
|
||||
{
|
||||
ToolStatic.OpenToolBox();
|
||||
}
|
||||
|
||||
public void OpenTraceLogger()
|
||||
{
|
||||
ToolStatic.OpenTraceLogger();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -661,6 +661,13 @@
|
|||
</Compile>
|
||||
<Compile Include="GLManager.cs" />
|
||||
<Compile Include="GlobalWin.cs" />
|
||||
<Compile Include="Api\ApiContainer.cs" />
|
||||
<Compile Include="Api\Libraries\ToolApi.cs" />
|
||||
<Compile Include="Api\Libraries\GuiApi.cs" />
|
||||
<Compile Include="Api\Libraries\InputApi.cs" />
|
||||
<Compile Include="Api\Libraries\SaveStateAPI.cs" />
|
||||
<Compile Include="Api\ApiManager.cs" />
|
||||
<Compile Include="Api\Libraries\CommApi.cs" />
|
||||
<!--<Compile Include="Input\GamePad.cs" Condition=" '$(OS)' == 'Windows_NT' " />-->
|
||||
<Compile Include="Input\GamePad.cs" />
|
||||
<Compile Include="Input\GamePad360.cs" />
|
||||
|
@ -734,7 +741,6 @@
|
|||
<Compile Include="NameStateForm.Designer.cs">
|
||||
<DependentUpon>NameStateForm.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="OpenAdvanced.cs" />
|
||||
<Compile Include="OpenAdvancedChooser.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using BizHawk.Bizware.BizwareGL;
|
||||
using BizHawk.Client.ApiHawk;
|
||||
|
||||
// ReSharper disable StyleCop.SA1401
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
|
@ -7,6 +8,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
{
|
||||
public static MainForm MainForm;
|
||||
public static ToolManager Tools;
|
||||
public static BasicApiProvider ApiProvider;
|
||||
|
||||
/// <summary>
|
||||
/// the IGL to be used for rendering
|
||||
|
|
|
@ -3783,6 +3783,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
ApiManager.Restart(Emulator.ServiceProvider);
|
||||
GlobalWin.Tools.Restart();
|
||||
|
||||
if (Global.Config.LoadCheatFileByGame)
|
||||
|
@ -3831,7 +3832,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
ClientApi.OnRomLoaded();
|
||||
ClientApi.OnRomLoaded(Emulator);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
@ -3842,10 +3843,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
// The ROM has been loaded by a recursive invocation of the LoadROM method.
|
||||
if (!(Emulator is NullEmulator))
|
||||
{
|
||||
ClientApi.OnRomLoaded();
|
||||
ClientApi.OnRomLoaded(Emulator);
|
||||
return true;
|
||||
}
|
||||
|
||||
ClientApi.UpdateEmulatorAndVP(Emulator);
|
||||
HandlePlatformMenus();
|
||||
_stateSlots.Clear();
|
||||
UpdateStatusSlots();
|
||||
|
@ -3935,6 +3937,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
var coreComm = CreateCoreComm();
|
||||
CoreFileProvider.SyncCoreCommInputSignals(coreComm);
|
||||
Emulator = new NullEmulator(coreComm, Global.Config.GetCoreSettings<NullEmulator>());
|
||||
ClientApi.UpdateEmulatorAndVP(Emulator);
|
||||
Global.ActiveController = new Controller(NullController.Instance.Definition);
|
||||
Global.AutoFireController = _autofireNullControls;
|
||||
RewireSound();
|
||||
|
@ -3957,6 +3960,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
Global.Game = GameInfo.NullInstance;
|
||||
|
||||
GlobalWin.Tools.Restart();
|
||||
ApiManager.Restart(Emulator.ServiceProvider);
|
||||
RewireSound();
|
||||
Text = "BizHawk" + (VersionInfo.DeveloperBuild ? " (interim) " : "");
|
||||
HandlePlatformMenus();
|
||||
|
|
|
@ -6,7 +6,7 @@ using System.Reflection;
|
|||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Client.ApiHawk;
|
||||
|
||||
namespace BizHawk.Client.EmuHawk
|
||||
{
|
||||
|
@ -66,6 +66,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
continue;
|
||||
if (!ServiceInjector.IsAvailable(Emulator.ServiceProvider, t))
|
||||
continue;
|
||||
// if (!ApiInjector.IsAvailable(, t))
|
||||
// continue;
|
||||
|
||||
var instance = Activator.CreateInstance(t);
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ using System.Reflection;
|
|||
using System.ComponentModel;
|
||||
using System.Windows.Forms;
|
||||
|
||||
using BizHawk.Client.ApiHawk;
|
||||
using BizHawk.Client.Common;
|
||||
using BizHawk.Client.EmuHawk;
|
||||
using BizHawk.Client.EmuHawk.CoreExtensions;
|
||||
|
@ -123,6 +124,11 @@ namespace BizHawk.Client.EmuHawk
|
|||
(newTool as Form).Owner = GlobalWin.MainForm;
|
||||
}
|
||||
|
||||
if (isExternal)
|
||||
{
|
||||
ApiInjector.UpdateApis(GlobalWin.ApiProvider, newTool);
|
||||
}
|
||||
|
||||
ServiceInjector.UpdateServices(Global.Emulator.ServiceProvider, newTool);
|
||||
string toolType = typeof(T).ToString();
|
||||
|
||||
|
@ -493,6 +499,8 @@ namespace BizHawk.Client.EmuHawk
|
|||
|
||||
if ((tool.IsHandleCreated && !tool.IsDisposed) || tool is RamWatch) // Hack for RAM Watch - in display watches mode it wants to keep running even closed, it will handle disposed logic
|
||||
{
|
||||
if (tool is IExternalToolForm)
|
||||
ApiInjector.UpdateApis(GlobalWin.ApiProvider, tool);
|
||||
tool.Restart();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,4 +110,4 @@
|
|||
<Target Name="AfterBuild">
|
||||
</Target>
|
||||
-->
|
||||
</Project>
|
||||
</Project>
|
|
@ -121,6 +121,10 @@
|
|||
<Compile Include="Sound\Utilities\Waves.cs" />
|
||||
<Compile Include="SystemLookup.cs" />
|
||||
<Compile Include="TextState.cs" />
|
||||
<Compile Include="WorkingTypes\wshort.cs" />
|
||||
<Compile Include="WorkingTypes\wushort.cs" />
|
||||
<Compile Include="WorkingTypes\wsbyte.cs" />
|
||||
<Compile Include="WorkingTypes\wbyte.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\BizHawk.Common\BizHawk.Common.csproj">
|
||||
|
|
|
@ -0,0 +1,116 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Security;
|
||||
|
||||
|
||||
namespace BizHawk.Emulation.Common.WorkingTypes
|
||||
{
|
||||
//
|
||||
// Summary:
|
||||
// Represents an 8-bit unsigned integer, that is capable of arithmetic without making you weep.
|
||||
// Also provides all the base functionality of the standard C# Byte by calling its methods where relevant.
|
||||
public unsafe class wbyte : IComparable, IFormattable, IComparable<wbyte>, IEquatable<wbyte>
|
||||
{
|
||||
private Byte val;
|
||||
public const Byte MaxValue = Byte.MaxValue;
|
||||
public const Byte MinValue = Byte.MinValue;
|
||||
public static implicit operator wbyte(ulong value)
|
||||
{
|
||||
return new wbyte(value);
|
||||
}
|
||||
public static implicit operator wbyte(wushort value)
|
||||
{
|
||||
return new wbyte(value);
|
||||
}
|
||||
public static implicit operator byte(wbyte value)
|
||||
{
|
||||
return value.val;
|
||||
}
|
||||
public wbyte()
|
||||
{
|
||||
|
||||
}
|
||||
public wbyte(ulong value)
|
||||
{
|
||||
val = (Byte)(value & 0xFF);
|
||||
}
|
||||
public wbyte(long value)
|
||||
{
|
||||
val = (Byte)(value & 0xFF);
|
||||
}
|
||||
public wbyte(double value)
|
||||
{
|
||||
val = (Byte)(((long)value) & 0xFF);
|
||||
}
|
||||
public static wbyte Parse(string s, NumberStyles style, IFormatProvider provider)
|
||||
{
|
||||
return (ulong)Byte.Parse(s, style, provider);
|
||||
}
|
||||
public static wbyte Parse(string s, IFormatProvider provider)
|
||||
{
|
||||
return (ulong)Byte.Parse(s, provider);
|
||||
}
|
||||
public static wbyte Parse(string s)
|
||||
{
|
||||
return (ulong)Byte.Parse(s);
|
||||
}
|
||||
public static wbyte Parse(string s, NumberStyles style)
|
||||
{
|
||||
return (ulong)Byte.Parse(s, style);
|
||||
}
|
||||
public static bool TryParse(string s, out wbyte result)
|
||||
{
|
||||
result = new wbyte();
|
||||
return byte.TryParse(s, out result.val);
|
||||
}
|
||||
public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out wbyte result)
|
||||
{
|
||||
result = new wbyte();
|
||||
return byte.TryParse(s, style, provider, out result.val);
|
||||
}
|
||||
public int CompareTo(wbyte value)
|
||||
{
|
||||
return val.CompareTo(value.val);
|
||||
}
|
||||
public int CompareTo(object value)
|
||||
{
|
||||
return val.CompareTo(value);
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return val.Equals(obj);
|
||||
}
|
||||
public bool Equals(wbyte obj)
|
||||
{
|
||||
return val.Equals(obj);
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return val.GetHashCode();
|
||||
}
|
||||
public TypeCode GetTypeCode()
|
||||
{
|
||||
return val.GetTypeCode();
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public string ToString(string format, IFormatProvider provider)
|
||||
{
|
||||
return val.ToString(format, provider);
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public override string ToString()
|
||||
{
|
||||
return val.ToString();
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public string ToString(string format)
|
||||
{
|
||||
return val.ToString(format);
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public string ToString(IFormatProvider provider)
|
||||
{
|
||||
return val.ToString(provider);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Security;
|
||||
|
||||
namespace BizHawk.Emulation.Common.WorkingTypes
|
||||
{
|
||||
//
|
||||
// Summary:
|
||||
// Represents an 8-bit unsigned integer, that is capable of arithmetic without making you weep.
|
||||
// Also provides all the base functionality of the standard C# SByte by calling its methods where relevant.
|
||||
public unsafe class wsbyte : IComparable, IFormattable, IComparable<wsbyte>, IEquatable<wsbyte>
|
||||
{
|
||||
private SByte val;
|
||||
public const SByte MaxValue = SByte.MaxValue;
|
||||
public const SByte MinValue = SByte.MinValue;
|
||||
public static implicit operator wsbyte(long value)
|
||||
{
|
||||
return new wsbyte(value);
|
||||
}
|
||||
public static implicit operator SByte(wsbyte value)
|
||||
{
|
||||
return value.val;
|
||||
}
|
||||
public wsbyte()
|
||||
{
|
||||
|
||||
}
|
||||
public wsbyte(long value)
|
||||
{
|
||||
val = (SByte)(value & 0xFF);
|
||||
}
|
||||
public wsbyte(ulong value)
|
||||
{
|
||||
val = (SByte)(value & 0xFF);
|
||||
}
|
||||
public wsbyte(double value)
|
||||
{
|
||||
val = (SByte)(((ulong)value) & 0xFF);
|
||||
}
|
||||
public static wsbyte Parse(string s, NumberStyles style, IFormatProvider provider)
|
||||
{
|
||||
return (long)SByte.Parse(s, style, provider);
|
||||
}
|
||||
public static wsbyte Parse(string s, IFormatProvider provider)
|
||||
{
|
||||
return (long)SByte.Parse(s, provider);
|
||||
}
|
||||
public static wsbyte Parse(string s)
|
||||
{
|
||||
return (long)SByte.Parse(s);
|
||||
}
|
||||
public static wsbyte Parse(string s, NumberStyles style)
|
||||
{
|
||||
return (long)SByte.Parse(s, style);
|
||||
}
|
||||
public static bool TryParse(string s, out wsbyte result)
|
||||
{
|
||||
result = new wsbyte();
|
||||
return SByte.TryParse(s, out result.val);
|
||||
}
|
||||
public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out wsbyte result)
|
||||
{
|
||||
result = new wsbyte();
|
||||
return SByte.TryParse(s, style, provider, out result.val);
|
||||
}
|
||||
public int CompareTo(wsbyte value)
|
||||
{
|
||||
return val.CompareTo(value.val);
|
||||
}
|
||||
public int CompareTo(object value)
|
||||
{
|
||||
return val.CompareTo(value);
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return val.Equals(obj);
|
||||
}
|
||||
public bool Equals(wsbyte obj)
|
||||
{
|
||||
return val.Equals(obj);
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return val.GetHashCode();
|
||||
}
|
||||
public TypeCode GetTypeCode()
|
||||
{
|
||||
return val.GetTypeCode();
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public string ToString(string format, IFormatProvider provider)
|
||||
{
|
||||
return val.ToString(format, provider);
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public override string ToString()
|
||||
{
|
||||
return val.ToString();
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public string ToString(string format)
|
||||
{
|
||||
return val.ToString(format);
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public string ToString(IFormatProvider provider)
|
||||
{
|
||||
return val.ToString(provider);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Security;
|
||||
|
||||
namespace BizHawk.Emulation.Common.WorkingTypes
|
||||
{
|
||||
//
|
||||
// Summary:
|
||||
// Represents an 16-bit unsigned integer, that is capable of arithmetic without making you weep.
|
||||
// Also provides all the base functionality of the standard C# Int16 by calling its methods where relevant.
|
||||
public unsafe class wshort : IComparable, IFormattable, IComparable<wshort>, IEquatable<wshort>
|
||||
{
|
||||
private Int16 val;
|
||||
public const Int16 MaxValue = Int16.MaxValue;
|
||||
public const Int16 MinValue = Int16.MinValue;
|
||||
public static implicit operator wshort(long value)
|
||||
{
|
||||
return new wshort(value);
|
||||
}
|
||||
public static implicit operator Int16(wshort value)
|
||||
{
|
||||
return value.val;
|
||||
}
|
||||
public wshort()
|
||||
{
|
||||
|
||||
}
|
||||
public wshort(long value)
|
||||
{
|
||||
val = (Int16)(value & 0xFFFF);
|
||||
}
|
||||
public wshort(ulong value)
|
||||
{
|
||||
val = (Int16)(value & 0xFFFF);
|
||||
}
|
||||
public wshort(double value)
|
||||
{
|
||||
val = (Int16)(((ulong)value) & 0xFFFF);
|
||||
}
|
||||
public static wshort Parse(string s, NumberStyles style, IFormatProvider provider)
|
||||
{
|
||||
return (long)Int16.Parse(s, style, provider);
|
||||
}
|
||||
public static wshort Parse(string s, IFormatProvider provider)
|
||||
{
|
||||
return (long)Int16.Parse(s, provider);
|
||||
}
|
||||
public static wshort Parse(string s)
|
||||
{
|
||||
return (long)Int16.Parse(s);
|
||||
}
|
||||
public static wshort Parse(string s, NumberStyles style)
|
||||
{
|
||||
return (long)Int16.Parse(s, style);
|
||||
}
|
||||
public static bool TryParse(string s, out wshort result)
|
||||
{
|
||||
result = new wshort();
|
||||
return Int16.TryParse(s, out result.val);
|
||||
}
|
||||
public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out wshort result)
|
||||
{
|
||||
result = new wshort();
|
||||
return Int16.TryParse(s, style, provider, out result.val);
|
||||
}
|
||||
public int CompareTo(wshort value)
|
||||
{
|
||||
return val.CompareTo(value.val);
|
||||
}
|
||||
public int CompareTo(object value)
|
||||
{
|
||||
return val.CompareTo(value);
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return val.Equals(obj);
|
||||
}
|
||||
public bool Equals(wshort obj)
|
||||
{
|
||||
return val.Equals(obj);
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return val.GetHashCode();
|
||||
}
|
||||
public TypeCode GetTypeCode()
|
||||
{
|
||||
return val.GetTypeCode();
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public string ToString(string format, IFormatProvider provider)
|
||||
{
|
||||
return val.ToString(format, provider);
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public override string ToString()
|
||||
{
|
||||
return val.ToString();
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public string ToString(string format)
|
||||
{
|
||||
return val.ToString(format);
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public string ToString(IFormatProvider provider)
|
||||
{
|
||||
return val.ToString(provider);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
using System;
|
||||
using System.Globalization;
|
||||
using System.Security;
|
||||
|
||||
|
||||
namespace BizHawk.Emulation.Common.WorkingTypes
|
||||
{
|
||||
//
|
||||
// Summary:
|
||||
// Represents an 16-bit unsigned integer, that is capable of arithmetic without making you weep.
|
||||
// Also provides all the base functionality of the standard C# UInt16 by calling its methods where relevant.
|
||||
public unsafe class wushort : IComparable, IFormattable, IComparable<wushort>, IEquatable<wushort>
|
||||
{
|
||||
private UInt16 val;
|
||||
public const UInt16 MaxValue = UInt16.MaxValue;
|
||||
public const UInt16 MinValue = UInt16.MinValue;
|
||||
public static implicit operator wushort(ulong value)
|
||||
{
|
||||
return new wushort(value);
|
||||
}
|
||||
public static implicit operator wushort(wbyte value)
|
||||
{
|
||||
return new wushort(value);
|
||||
}
|
||||
public static implicit operator UInt16(wushort value)
|
||||
{
|
||||
return value.val;
|
||||
}
|
||||
public wushort()
|
||||
{
|
||||
|
||||
}
|
||||
public wushort(ulong value)
|
||||
{
|
||||
val = (UInt16)(value & 0xFFFF);
|
||||
}
|
||||
public wushort(long value)
|
||||
{
|
||||
val = (UInt16)(value & 0xFFFF);
|
||||
}
|
||||
public wushort(double value)
|
||||
{
|
||||
val = (UInt16)(((long)value) & 0xFFFF);
|
||||
}
|
||||
public static wushort Parse(string s, NumberStyles style, IFormatProvider provider)
|
||||
{
|
||||
return (uint)UInt16.Parse(s, style, provider);
|
||||
}
|
||||
public static wushort Parse(string s, IFormatProvider provider)
|
||||
{
|
||||
return (uint)UInt16.Parse(s, provider);
|
||||
}
|
||||
public static wushort Parse(string s)
|
||||
{
|
||||
return (uint)UInt16.Parse(s);
|
||||
}
|
||||
public static wushort Parse(string s, NumberStyles style)
|
||||
{
|
||||
return (uint)UInt16.Parse(s, style);
|
||||
}
|
||||
public static bool TryParse(string s, out wushort result)
|
||||
{
|
||||
result = new wushort();
|
||||
return ushort.TryParse(s, out result.val);
|
||||
}
|
||||
public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out wushort result)
|
||||
{
|
||||
result = new wushort();
|
||||
return ushort.TryParse(s, style, provider, out result.val);
|
||||
}
|
||||
public int CompareTo(wushort value)
|
||||
{
|
||||
return val.CompareTo(value.val);
|
||||
}
|
||||
public int CompareTo(object value)
|
||||
{
|
||||
return val.CompareTo(value);
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return val.Equals(obj);
|
||||
}
|
||||
public bool Equals(wushort obj)
|
||||
{
|
||||
return val.Equals(obj);
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return val.GetHashCode();
|
||||
}
|
||||
public TypeCode GetTypeCode()
|
||||
{
|
||||
return val.GetTypeCode();
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public string ToString(string format, IFormatProvider provider)
|
||||
{
|
||||
return val.ToString(format, provider);
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public override string ToString()
|
||||
{
|
||||
return val.ToString();
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public string ToString(string format)
|
||||
{
|
||||
return val.ToString(format);
|
||||
}
|
||||
[SecuritySafeCritical]
|
||||
public string ToString(IFormatProvider provider)
|
||||
{
|
||||
return val.ToString(provider);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.27703.2047
|
||||
MinimumVisualStudioVersion = 12.0.31101.0
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Version", "Version\Version.csproj", "{0CE8B337-08E3-4602-BF10-C4D4C75D2F13}"
|
||||
EndProject
|
||||
|
@ -264,6 +264,9 @@ Global
|
|||
{B95649F5-A0AE-41EB-B62B-578A2AFF5E18} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA}
|
||||
{8E2F11F2-3955-4382-8C3A-CEBA1276CAEA} = {B51F1139-3D2C-41BE-A762-EF1F9B41EACA}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {1A77376C-2741-489C-90E1-03E415910B65}
|
||||
EndGlobalSection
|
||||
GlobalSection(MonoDevelopProperties) = preSolution
|
||||
StartupItem = BizHawk.Client.EmuHawk\BizHawk.Client.EmuHawk.csproj
|
||||
EndGlobalSection
|
||||
|
|
|
@ -860,7 +860,7 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.OpenTK
|
|||
_rsBlendNormal = new CacheBlendState(
|
||||
true,
|
||||
BlendingFactorSrc.SrcAlpha, BlendEquationMode.FuncAdd, BlendingFactorDest.OneMinusSrcAlpha,
|
||||
BlendingFactorSrc.One, BlendEquationMode.FuncAdd, BlendingFactorDest.Zero);
|
||||
BlendingFactorSrc.One, BlendEquationMode.Max, BlendingFactorDest.One);
|
||||
}
|
||||
|
||||
CacheBlendState _rsBlendNoneVerbatim, _rsBlendNoneOpaque, _rsBlendNormal;
|
||||
|
|
|
@ -368,7 +368,7 @@ namespace BizHawk.Bizware.BizwareGL.Drivers.SlimDX
|
|||
_rsBlendNormal = new CacheBlendState(
|
||||
true,
|
||||
gl.BlendingFactorSrc.SrcAlpha, gl.BlendEquationMode.FuncAdd, gl.BlendingFactorDest.OneMinusSrcAlpha,
|
||||
gl.BlendingFactorSrc.One, gl.BlendEquationMode.FuncAdd, gl.BlendingFactorDest.Zero);
|
||||
gl.BlendingFactorSrc.One, gl.BlendEquationMode.Max, gl.BlendingFactorDest.One);
|
||||
}
|
||||
|
||||
CacheBlendState _rsBlendNoneVerbatim, _rsBlendNoneOpaque, _rsBlendNormal;
|
||||
|
|
|
@ -287,7 +287,7 @@ namespace BizHawk.Bizware.BizwareGL
|
|||
/// </summary>
|
||||
public void DiscardAlpha()
|
||||
{
|
||||
HasAlpha = false;
|
||||
//HasAlpha = false;
|
||||
}
|
||||
|
||||
void LoadInternal(Stream stream, sd.Bitmap bitmap, BitmapLoadOptions options)
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit 7432d1f40808b22d3ef7e403cf7ae45b1061dcd7
|
||||
Subproject commit 57ba873c5e117a42f94299cb7ddaa1066249b416
|
Loading…
Reference in New Issue