Merge branch 'master' into appleii_fixattempt
This commit is contained in:
commit
59ad94f9b9
|
@ -73,3 +73,4 @@ ExternalCoreProjects/Virtu/bin/*.*
|
|||
libsnes/vs2015/libsnes.VC.db
|
||||
waterbox/**/*.wbx
|
||||
waterbox/**/*.wbx.in
|
||||
/BizHawkTool_template.zip
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/sh
|
||||
cd "$(dirname "$0")"
|
||||
if [ "$(ps -C "mono" -o "cmd" --no-headers | grep "EmuHawk.exe")" ]; then
|
||||
echo "EmuHawk is already running, exiting..."
|
||||
exit 0
|
||||
fi
|
||||
libpath=""
|
||||
if [ "$(command -v lsb_release)" ]; then
|
||||
case "$(lsb_release -i | cut -c17- | tr -d "\n")" in
|
||||
"Arch"|"ManjaroLinux") libpath="/usr/lib/wine";;
|
||||
"Debian"|"Ubuntu"|"LinuxMint") libpath="/usr/lib/x86_64-linux-gnu/wine";;
|
||||
esac
|
||||
fi
|
||||
if [ -z "$libpath" ]; then
|
||||
printf "%s\n" "Unknown distro, assuming WINE library location is /usr/lib/wine..."
|
||||
libpath="/usr/lib/wine"
|
||||
fi
|
||||
LD_LIBRARY_PATH="$libpath" mono ./EmuHawk.exe
|
3020
Assets/defctrl.json
3020
Assets/defctrl.json
File diff suppressed because it is too large
Load Diff
|
@ -2699,3 +2699,4 @@ sha1:00CCF622E7BA4D0A39DCBABAB771CE815B0FB8FE Boulder Dash (2005) (Andrew Davie
|
|||
sha1:650DA2339D41D1D2F180A6CAFE8DC311AC588ACD Boulder Dash Intro Tune (2005) (Erik Ehrling) A26 m=4K;NTSC=true
|
||||
sha1:F28E52921646A18467577370808454F494C15EFE 0840 EconoBanking A26 m=0840;NTSC=true
|
||||
sha1:2A9647E27AB27E6CF82B3BF122EDF212FA34AE86 Halo2600 Final A26 m=m4K
|
||||
sha1:341BB93E67C21063F3910845D1AF59FEA129FF21 Bang! A26 m=F4SC
|
|
@ -346,6 +346,7 @@ sha1:D89EE629F8F60613999EAD84A3C7B2F6B38C399F fme7ramtest_128k NES board=MAPPE
|
|||
sha1:78C4441E42C8F423EBF6558AA00AB6D0DBCC2B4B 34_test_1 NES board=AVE-NINA-01;PRG=64;CHR=64;WRAM=8;VRAM=0;PAD_V=1;PAD_H=0
|
||||
sha1:F2D5CB78D78831CB6A2A17CD418A753F3C99C7F4 34_test_2 NES board=NES-BNROM;PRG=256;CHR=0;WRAM=8;VRAM=8;PAD_V=1;PAD_H=0
|
||||
sha1:77C5C2473AF13003B7BD8273A5E23BE4964107A3 M34_P128K_H NES board=AVE-NINA-07;PRG=128;CHR=0;WRAM=0;VRAM=8;PAD_V=1;PAD_H=0
|
||||
sha1:B6721E1C1EC2E2F215180ED7BB31EDA80BCDE869 2nd2006_next_level NES board=MAPPER000;PRG=16;CHR=8;PAD_V=1;PAD_H=0
|
||||
|
||||
;other
|
||||
sha1:4180276C50DF9958DEDD6C6D19C9E7AEBB75A89F o Galaxian (Japan) NES board=NAMCOT-3301;PRG=16;CHR=8;WRAM=8;VRAM=0;PAD_V=1;PAD_H=0
|
||||
|
|
Binary file not shown.
|
@ -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 {nameof(IDisassemblable.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 {nameof(IDebuggable.GetCpuFlagsAndRegisters)}()");
|
||||
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 {nameof(IDebuggable.GetCpuFlagsAndRegisters)}()");
|
||||
}
|
||||
|
||||
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 {nameof(IDebuggable.SetCpuRegister)}()");
|
||||
}
|
||||
}
|
||||
|
||||
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 {nameof(IDebuggable.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 {nameof(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 {nameof(IInputPollable)}");
|
||||
}
|
||||
}
|
||||
|
||||
public int LagCount()
|
||||
{
|
||||
if (InputPollableCore != null)
|
||||
{
|
||||
return InputPollableCore.LagCount;
|
||||
}
|
||||
|
||||
Console.WriteLine($"Can not get lag information, {Emulator.Attributes().CoreName} does not implement {nameof(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 {nameof(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 {nameof(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 {nameof(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}"] = 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -102,6 +102,9 @@ namespace BizHawk.Client.ApiHawk
|
|||
case "AmstradCPC":
|
||||
return CoreSystem.AmstradCPC;
|
||||
|
||||
case "GGL":
|
||||
return CoreSystem.GGL;
|
||||
|
||||
case "VB":
|
||||
case "NGP":
|
||||
case "DNGP":
|
||||
|
@ -112,7 +115,7 @@ namespace BizHawk.Client.ApiHawk
|
|||
return 0; // like I give a shit
|
||||
|
||||
default:
|
||||
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value));
|
||||
throw new IndexOutOfRangeException($"{value} is missing in convert list");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -218,7 +221,7 @@ namespace BizHawk.Client.ApiHawk
|
|||
return "AmstradCPC";
|
||||
|
||||
default:
|
||||
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value.ToString()));
|
||||
throw new IndexOutOfRangeException($"{value.ToString()} is missing in convert list");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
@ -108,7 +145,7 @@ namespace BizHawk.Client.ApiHawk
|
|||
{
|
||||
if (player < 1 || player > RunningSystem.MaxControllers)
|
||||
{
|
||||
throw new IndexOutOfRangeException(string.Format("{0} does not support {1} controller(s)", RunningSystem.DisplayName, player));
|
||||
throw new IndexOutOfRangeException($"{RunningSystem.DisplayName} does not support {player} controller(s)");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -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), $"{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), $"{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>
|
||||
|
@ -280,7 +358,7 @@ namespace BizHawk.Client.ApiHawk
|
|||
{
|
||||
if (player < 1 || player > RunningSystem.MaxControllers)
|
||||
{
|
||||
throw new IndexOutOfRangeException(string.Format("{0} does not support {1} controller(s)", RunningSystem.DisplayName, player));
|
||||
throw new IndexOutOfRangeException($"{RunningSystem.DisplayName} does not support {player} controller(s)");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -298,11 +376,11 @@ namespace BizHawk.Client.ApiHawk
|
|||
AutoFireStickyXorAdapter joypadAdaptor = Global.AutofireStickyXORAdapter;
|
||||
if (RunningSystem == SystemInfo.GB)
|
||||
{
|
||||
joypadAdaptor.SetSticky(string.Format("{0}", JoypadConverter.ConvertBack(button, RunningSystem)), true);
|
||||
joypadAdaptor.SetSticky($"{JoypadConverter.ConvertBack(button, RunningSystem)}", true);
|
||||
}
|
||||
else
|
||||
{
|
||||
joypadAdaptor.SetSticky(string.Format("P{0} {1}", player, JoypadConverter.ConvertBack(button, RunningSystem)), true);
|
||||
joypadAdaptor.SetSticky($"P{player} {JoypadConverter.ConvertBack(button, RunningSystem)}", true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -314,8 +392,8 @@ namespace BizHawk.Client.ApiHawk
|
|||
AutoFireStickyXorAdapter joypadAdaptor = Global.AutofireStickyXORAdapter;
|
||||
for (int i = 1; i <= RunningSystem.MaxControllers; i++)
|
||||
{
|
||||
joypadAdaptor.SetFloat(string.Format("P{0} X Axis", i), allJoypads[i - 1].AnalogX);
|
||||
joypadAdaptor.SetFloat(string.Format("P{0} Y Axis", i), allJoypads[i - 1].AnalogY);
|
||||
joypadAdaptor.SetFloat($"P{i} X Axis", allJoypads[i - 1].AnalogX);
|
||||
joypadAdaptor.SetFloat($"P{i} Y Axis", allJoypads[i - 1].AnalogY);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
|
@ -369,12 +446,281 @@ namespace BizHawk.Client.ApiHawk
|
|||
{
|
||||
for (int i = 1; i <= RunningSystem.MaxControllers; i++)
|
||||
{
|
||||
allJoypads[i - 1].AnalogX = joypadAdaptor.GetFloat(string.Format("P{0} X Axis", i));
|
||||
allJoypads[i - 1].AnalogY = joypadAdaptor.GetFloat(string.Format("P{0} Y Axis", i));
|
||||
allJoypads[i - 1].AnalogX = joypadAdaptor.GetFloat($"P{i} X Axis");
|
||||
allJoypads[i - 1].AnalogY = joypadAdaptor.GetFloat($"P{i} Y Axis");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -94,7 +94,7 @@ namespace BizHawk.Client.ApiHawk
|
|||
item.ToolTipText = attribute.Description;
|
||||
if (attribute.IconResourceName != "")
|
||||
{
|
||||
Stream s = externalToolFile.GetManifestResourceStream(string.Format("{0}.{1}", externalToolFile.GetName().Name, attribute.IconResourceName));
|
||||
Stream s = externalToolFile.GetManifestResourceStream($"{externalToolFile.GetName().Name}.{attribute.IconResourceName}");
|
||||
if (s != null)
|
||||
{
|
||||
item.Image = new Bitmap(s);
|
||||
|
|
|
@ -29,7 +29,7 @@ namespace BizHawk.Client.ApiHawk
|
|||
{
|
||||
if (player < 1 || player > system.MaxControllers)
|
||||
{
|
||||
throw new InvalidOperationException(string.Format("{0} is invalid for {1}", player, system.DisplayName));
|
||||
throw new InvalidOperationException($"{player} is invalid for {system.DisplayName}");
|
||||
}
|
||||
|
||||
_System = system;
|
||||
|
|
|
@ -91,7 +91,7 @@ namespace BizHawk.Client.ApiHawk
|
|||
return JoypadButton.R;
|
||||
|
||||
default:
|
||||
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value));
|
||||
throw new IndexOutOfRangeException($"{value} is missing in convert list");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,7 +210,7 @@ namespace BizHawk.Client.ApiHawk
|
|||
return "R";
|
||||
|
||||
default:
|
||||
throw new IndexOutOfRangeException(string.Format("{0} is missing in convert list", value));
|
||||
throw new IndexOutOfRangeException($"{value} is missing in convert list");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -14,6 +14,8 @@
|
|||
along with SevenZipSharp. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
using BizHawk.Common;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
#if !WINCE && !MONO
|
||||
|
@ -61,7 +63,7 @@ namespace SevenZip
|
|||
/// 7z.dll (from the 7-zip distribution) supports every InArchiveFormat for encoding and decoding.
|
||||
/// </remarks>
|
||||
//private static string _libraryFileName = ConfigurationManager.AppSettings["7zLocation"] ?? Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "7z.dll");
|
||||
private static string _libraryFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "7z.dll");
|
||||
private static string _libraryFileName = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), "dll\\7z.dll");
|
||||
|
||||
#endif
|
||||
#if WINCE
|
||||
|
@ -87,6 +89,8 @@ namespace SevenZip
|
|||
// private static string _LibraryVersion;
|
||||
private static bool? _modifyCapabale;
|
||||
|
||||
private static readonly PlatformLinkedLibSingleton.PlatformLinkedLibManager libLoader = PlatformLinkedLibSingleton.LinkedLibManager;
|
||||
|
||||
private static void InitUserInFormat(object user, InArchiveFormat format)
|
||||
{
|
||||
if (!_inArchives.ContainsKey(user))
|
||||
|
@ -148,16 +152,16 @@ namespace SevenZip
|
|||
//{
|
||||
// throw new SevenZipLibraryException("DLL file does not exist.");
|
||||
//}
|
||||
if ((_modulePtr = NativeMethods.LoadLibrary(_libraryFileName)) == IntPtr.Zero)
|
||||
if ((_modulePtr = libLoader.LoadPlatformSpecific(_libraryFileName)) == IntPtr.Zero)
|
||||
{
|
||||
//try a different directory
|
||||
string alternateFilename = Path.Combine(Path.Combine(Path.GetDirectoryName(_libraryFileName),"dll"),"7z.dll");
|
||||
if ((_modulePtr = NativeMethods.LoadLibrary(alternateFilename)) == IntPtr.Zero)
|
||||
if ((_modulePtr = libLoader.LoadPlatformSpecific(alternateFilename)) == IntPtr.Zero)
|
||||
throw new SevenZipLibraryException("failed to load library.");
|
||||
}
|
||||
if (NativeMethods.GetProcAddress(_modulePtr, "GetHandlerProperty") == IntPtr.Zero)
|
||||
if (libLoader.GetProcAddr(_modulePtr, "GetHandlerProperty") == IntPtr.Zero)
|
||||
{
|
||||
NativeMethods.FreeLibrary(_modulePtr);
|
||||
libLoader.FreePlatformSpecific(_modulePtr);
|
||||
throw new SevenZipLibraryException("library is invalid.");
|
||||
}
|
||||
}
|
||||
|
@ -431,7 +435,7 @@ namespace SevenZip
|
|||
if (_totalUsers == 0)
|
||||
{
|
||||
#if !WINCE && !MONO
|
||||
NativeMethods.FreeLibrary(_modulePtr);
|
||||
libLoader.FreePlatformSpecific(_modulePtr);
|
||||
|
||||
#endif
|
||||
_modulePtr = IntPtr.Zero;
|
||||
|
@ -466,7 +470,7 @@ namespace SevenZip
|
|||
}
|
||||
var createObject = (NativeMethods.CreateObjectDelegate)
|
||||
Marshal.GetDelegateForFunctionPointer(
|
||||
NativeMethods.GetProcAddress(_modulePtr, "CreateObject"),
|
||||
libLoader.GetProcAddr(_modulePtr, "CreateObject"),
|
||||
typeof(NativeMethods.CreateObjectDelegate));
|
||||
if (createObject == null)
|
||||
{
|
||||
|
@ -525,7 +529,7 @@ namespace SevenZip
|
|||
}
|
||||
var createObject = (NativeMethods.CreateObjectDelegate)
|
||||
Marshal.GetDelegateForFunctionPointer(
|
||||
NativeMethods.GetProcAddress(_modulePtr, "CreateObject"),
|
||||
libLoader.GetProcAddr(_modulePtr, "CreateObject"),
|
||||
typeof(NativeMethods.CreateObjectDelegate));
|
||||
if (createObject == null)
|
||||
{
|
||||
|
|
|
@ -35,18 +35,8 @@ namespace SevenZip
|
|||
[MarshalAs(UnmanagedType.Interface)] out object outObject);
|
||||
|
||||
#endregion
|
||||
|
||||
[DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||
public static extern IntPtr LoadLibrary([MarshalAs(UnmanagedType.LPStr)] string fileName);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
public static extern bool FreeLibrary(IntPtr hModule);
|
||||
|
||||
[DllImport("kernel32.dll", BestFitMapping = false, ThrowOnUnmappableChar = true)]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, [MarshalAs(UnmanagedType.LPStr)] string procName);
|
||||
#endif
|
||||
|
||||
|
||||
#if WINCE
|
||||
[DllImport("7z.dll", EntryPoint="CreateObject")]
|
||||
public static extern int CreateCOMObject(
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
VirtualBoy,
|
||||
NeoGeoPocket,
|
||||
ZXSpectrum,
|
||||
AmstradCPC
|
||||
AmstradCPC,
|
||||
GGL
|
||||
}
|
||||
}
|
||||
|
|
|
@ -260,7 +260,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (abort)
|
||||
{
|
||||
throw new Exception("Essential zip section not found: " + lump.ReadName);
|
||||
throw new Exception($"Essential zip section not found: {lump.ReadName}");
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -53,7 +53,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
if (required)
|
||||
{
|
||||
var fullmsg = $"Couldn't find required firmware \"{sysID}:{firmwareID}\". This is fatal{(msg != null ? ": " + msg : ".")}";
|
||||
var fullmsg = $"Couldn't find required firmware \"{sysID}:{firmwareID}\". This is fatal{(msg != null ? $": {msg}" : ".")}";
|
||||
throw new MissingFirmwareException(fullmsg);
|
||||
}
|
||||
|
||||
|
|
|
@ -159,7 +159,5 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
|
||||
public static Dictionary<string, object> UserBag = new Dictionary<string, object>();
|
||||
|
||||
public static bool RunningOnUnix = Environment.OSVersion.Platform == PlatformID.Unix || Environment.OSVersion.Platform == PlatformID.MacOSX;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
@ -60,7 +60,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
else if (type == OpenAdvancedTypes.LibretroNoGame) ioa = new OpenAdvanced_LibretroNoGame();
|
||||
else ioa = null;
|
||||
if (ioa == null)
|
||||
throw new InvalidOperationException("IOpenAdvanced deserialization error");
|
||||
throw new InvalidOperationException($"{nameof(IOpenAdvanced)} deserialization error");
|
||||
ioa.Deserialize(token);
|
||||
return ioa;
|
||||
}
|
||||
|
@ -74,7 +74,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
}
|
||||
}
|
||||
|
||||
class OpenAdvanced_Libretro : IOpenAdvanced, IOpenAdvancedLibretro
|
||||
public class OpenAdvanced_Libretro : IOpenAdvanced, IOpenAdvancedLibretro
|
||||
{
|
||||
public OpenAdvanced_Libretro()
|
||||
{
|
||||
|
@ -87,7 +87,7 @@ namespace BizHawk.Client.EmuHawk
|
|||
public Token token = new Token();
|
||||
|
||||
public string TypeName { get { return "Libretro"; } }
|
||||
public string DisplayName { get { return string.Format("{0}:{1}", Path.GetFileNameWithoutExtension(token.CorePath), token.Path); } }
|
||||
public string DisplayName { get { return $"{Path.GetFileNameWithoutExtension(token.CorePath)}:{token.Path}"; } }
|
||||
public string SimplePath { get { return token.Path; } }
|
||||
|
||||
public void Deserialize(string str)
|
||||
|
@ -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()
|
||||
{}
|
|
@ -13,6 +13,11 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
public static class PathManager
|
||||
{
|
||||
static PathManager()
|
||||
{
|
||||
SetDefaultIniPath(MakeProgramRelativePath("config.ini"));
|
||||
}
|
||||
|
||||
public static string GetExeDirectoryAbsolute()
|
||||
{
|
||||
var path = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
|
@ -29,7 +34,7 @@ namespace BizHawk.Client.Common
|
|||
/// </summary>
|
||||
public static string MakeProgramRelativePath(string path)
|
||||
{
|
||||
return MakeAbsolutePath("%exe%/" + path, null);
|
||||
return MakeAbsolutePath($"%exe%/{path}", null);
|
||||
}
|
||||
|
||||
public static string GetDllDirectory()
|
||||
|
@ -40,7 +45,12 @@ namespace BizHawk.Client.Common
|
|||
/// <summary>
|
||||
/// The location of the default INI file
|
||||
/// </summary>
|
||||
public static string DefaultIniPath => MakeProgramRelativePath("config.ini");
|
||||
public static string DefaultIniPath { get; private set; }
|
||||
|
||||
public static void SetDefaultIniPath(string newDefaultIniPath)
|
||||
{
|
||||
DefaultIniPath = newDefaultIniPath;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets absolute base as derived from EXE
|
||||
|
@ -252,13 +262,13 @@ namespace BizHawk.Client.Common
|
|||
var name = FilesystemSafeName(game);
|
||||
if (Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
name += "." + Path.GetFileNameWithoutExtension(Global.MovieSession.Movie.Filename);
|
||||
name += $".{Path.GetFileNameWithoutExtension(Global.MovieSession.Movie.Filename)}";
|
||||
}
|
||||
|
||||
var pathEntry = Global.Config.PathEntries[game.System, "Save RAM"] ??
|
||||
Global.Config.PathEntries[game.System, "Base"];
|
||||
|
||||
return Path.Combine(MakeAbsolutePath(pathEntry.Path, game.System), name) + ".SaveRAM";
|
||||
return $"{Path.Combine(MakeAbsolutePath(pathEntry.Path, game.System), name)}.SaveRAM";
|
||||
}
|
||||
|
||||
public static string AutoSaveRamPath(GameInfo game)
|
||||
|
@ -279,7 +289,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
name = Path.Combine(name, "movie-" + Path.GetFileNameWithoutExtension(Global.MovieSession.Movie.Filename));
|
||||
name = Path.Combine(name, $"movie-{Path.GetFileNameWithoutExtension(Global.MovieSession.Movie.Filename)}");
|
||||
}
|
||||
|
||||
var pathEntry = Global.Config.PathEntries[game.System, "Save RAM"] ??
|
||||
|
@ -327,34 +337,34 @@ namespace BizHawk.Client.Common
|
|||
// Neshawk and Quicknes have incompatible savestates, store the name to keep them separate
|
||||
if (Global.Emulator.SystemId == "NES")
|
||||
{
|
||||
name += "." + Global.Emulator.Attributes().CoreName;
|
||||
name += $".{Global.Emulator.Attributes().CoreName}";
|
||||
}
|
||||
|
||||
// Gambatte and GBHawk have incompatible savestates, store the name to keep them separate
|
||||
if (Global.Emulator.SystemId == "GB")
|
||||
{
|
||||
name += "." + Global.Emulator.Attributes().CoreName;
|
||||
name += $".{Global.Emulator.Attributes().CoreName}";
|
||||
}
|
||||
|
||||
if (Global.Emulator is Snes9x) // Keep snes9x savestate away from libsnes, we want to not be too tedious so bsnes names will just have the profile name not the core name
|
||||
{
|
||||
name += "." + Global.Emulator.Attributes().CoreName;
|
||||
name += $".{Global.Emulator.Attributes().CoreName}";
|
||||
}
|
||||
|
||||
// Bsnes profiles have incompatible savestates so save the profile name
|
||||
if (Global.Emulator is LibsnesCore)
|
||||
{
|
||||
name += "." + (Global.Emulator as LibsnesCore).CurrentProfile;
|
||||
name += $".{((LibsnesCore)Global.Emulator).CurrentProfile}";
|
||||
}
|
||||
|
||||
if (Global.Emulator.SystemId == "GBA")
|
||||
{
|
||||
name += "." + Global.Emulator.Attributes().CoreName;
|
||||
name += $".{Global.Emulator.Attributes().CoreName}";
|
||||
}
|
||||
|
||||
if (Global.MovieSession.Movie.IsActive)
|
||||
{
|
||||
name += "." + Path.GetFileNameWithoutExtension(Global.MovieSession.Movie.Filename);
|
||||
name += $".{Path.GetFileNameWithoutExtension(Global.MovieSession.Movie.Filename)}";
|
||||
}
|
||||
|
||||
var pathEntry = Global.Config.PathEntries[game.System, "Savestates"] ??
|
||||
|
|
|
@ -14,8 +14,10 @@ using BizHawk.Emulation.Cores.Computers.Commodore64;
|
|||
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
|
||||
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
|
||||
using BizHawk.Emulation.Cores.Nintendo.GBHawk;
|
||||
using BizHawk.Emulation.Cores.Nintendo.GBHawkLink;
|
||||
using BizHawk.Emulation.Cores.Nintendo.SNES;
|
||||
using BizHawk.Emulation.Cores.PCEngine;
|
||||
using BizHawk.Emulation.Cores.Sega.GGHawkLink;
|
||||
using BizHawk.Emulation.Cores.Sega.Saturn;
|
||||
using BizHawk.Emulation.Cores.Sony.PSP;
|
||||
using BizHawk.Emulation.Cores.Sony.PSX;
|
||||
|
@ -217,7 +219,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
else if (discMountJob.OUT_ErrorLevel)
|
||||
{
|
||||
throw new InvalidOperationException("\r\n" + discMountJob.OUT_Log);
|
||||
throw new InvalidOperationException($"\r\n{discMountJob.OUT_Log}");
|
||||
}
|
||||
|
||||
else if (disc == null)
|
||||
|
@ -426,7 +428,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (discMountJob.OUT_ErrorLevel)
|
||||
{
|
||||
throw new InvalidOperationException("\r\n" + discMountJob.OUT_Log);
|
||||
throw new InvalidOperationException($"\r\n{discMountJob.OUT_Log}");
|
||||
}
|
||||
|
||||
if (disc == null)
|
||||
|
@ -494,7 +496,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (discMountJob.OUT_ErrorLevel)
|
||||
{
|
||||
throw new InvalidOperationException("\r\n" + discMountJob.OUT_Log);
|
||||
throw new InvalidOperationException($"\r\n{discMountJob.OUT_Log}");
|
||||
}
|
||||
|
||||
var disc = discMountJob.OUT_Disc;
|
||||
|
@ -630,7 +632,20 @@ namespace BizHawk.Client.Common
|
|||
|
||||
var left = Database.GetGameInfo(leftBytes, "left.gb");
|
||||
var right = Database.GetGameInfo(rightBytes, "right.gb");
|
||||
nextEmulator = new GambatteLink(
|
||||
if (Global.Config.GB_UseGBHawk)
|
||||
{
|
||||
nextEmulator = new GBHawkLink(
|
||||
nextComm,
|
||||
left,
|
||||
leftBytes,
|
||||
right,
|
||||
rightBytes,
|
||||
GetCoreSettings<GBHawkLink>(),
|
||||
GetCoreSyncSettings<GBHawkLink>());
|
||||
}
|
||||
else
|
||||
{
|
||||
nextEmulator = new GambatteLink(
|
||||
nextComm,
|
||||
left,
|
||||
leftBytes,
|
||||
|
@ -639,7 +654,8 @@ namespace BizHawk.Client.Common
|
|||
GetCoreSettings<GambatteLink>(),
|
||||
GetCoreSyncSettings<GambatteLink>(),
|
||||
Deterministic);
|
||||
|
||||
}
|
||||
|
||||
// other stuff todo
|
||||
break;
|
||||
case "AppleII":
|
||||
|
@ -713,7 +729,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (discMountJob.OUT_ErrorLevel)
|
||||
{
|
||||
throw new InvalidOperationException("\r\n" + discMountJob.OUT_Log);
|
||||
throw new InvalidOperationException($"\r\n{discMountJob.OUT_Log}");
|
||||
}
|
||||
|
||||
if (disc == null)
|
||||
|
@ -790,6 +806,22 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
nextEmulator = new GPGX(nextComm, null, genDiscs, GetCoreSettings<GPGX>(), GetCoreSyncSettings<GPGX>());
|
||||
break;
|
||||
case "Game Gear":
|
||||
var leftBytesGG = xmlGame.Assets.First().Value;
|
||||
var rightBytesGG = xmlGame.Assets.Skip(1).First().Value;
|
||||
|
||||
var leftGG = Database.GetGameInfo(leftBytesGG, "left.gg");
|
||||
var rightGG = Database.GetGameInfo(rightBytesGG, "right.gg");
|
||||
|
||||
nextEmulator = new GGHawkLink(
|
||||
nextComm,
|
||||
leftGG,
|
||||
leftBytesGG,
|
||||
rightGG,
|
||||
rightBytesGG,
|
||||
GetCoreSettings<GGHawkLink>(),
|
||||
GetCoreSyncSettings<GGHawkLink>());
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
@ -958,7 +990,14 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (preference == "neshawk")
|
||||
{
|
||||
core = CoreInventory.Instance["NES", "NesHawk"];
|
||||
if (Global.Config.UseSubNESHawk)
|
||||
{
|
||||
core = CoreInventory.Instance["NES", "SubNESHawk"];
|
||||
}
|
||||
else
|
||||
{
|
||||
core = CoreInventory.Instance["NES", "NesHawk"];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1132,12 +1171,12 @@ namespace BizHawk.Client.Common
|
|||
// handle exceptions thrown by the new detected systems that bizhawk does not have cores for
|
||||
else if (ex is NoAvailableCoreException)
|
||||
{
|
||||
DoLoadErrorCallback(ex.Message + "\n\n" + ex, system);
|
||||
DoLoadErrorCallback($"{ex.Message}\n\n{ex}", system);
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
DoLoadErrorCallback("A core accepted the rom, but threw an exception while loading it:\n\n" + ex, system);
|
||||
DoLoadErrorCallback($"A core accepted the rom, but threw an exception while loading it:\n\n{ex}", system);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -29,8 +29,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
var file = new FileInfo(
|
||||
PathManager.SaveStatePrefix(Global.Game) + "." + "QuickSave" + i + ".State");
|
||||
var file = new FileInfo($"{PathManager.SaveStatePrefix(Global.Game)}.QuickSave{i}.State");
|
||||
if (file.Directory != null && file.Directory.Exists == false)
|
||||
{
|
||||
file.Directory.Create();
|
||||
|
@ -108,8 +107,8 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
// Takes the .state and .bak files and swaps them
|
||||
var state = new FileInfo(path);
|
||||
var backup = new FileInfo(path + ".bak");
|
||||
var temp = new FileInfo(path + ".bak.tmp");
|
||||
var backup = new FileInfo($"{path}.bak");
|
||||
var temp = new FileInfo($"{path}.bak.tmp");
|
||||
|
||||
if (!state.Exists || !backup.Exists)
|
||||
{
|
||||
|
@ -121,9 +120,9 @@ namespace BizHawk.Client.Common
|
|||
temp.Delete();
|
||||
}
|
||||
|
||||
backup.CopyTo(path + ".bak.tmp");
|
||||
backup.CopyTo($"{path}.bak.tmp");
|
||||
backup.Delete();
|
||||
state.CopyTo(path + ".bak");
|
||||
state.CopyTo($"{path}.bak");
|
||||
state.Delete();
|
||||
temp.CopyTo(path);
|
||||
temp.Delete();
|
||||
|
|
|
@ -198,14 +198,19 @@ namespace BizHawk.Client.Common
|
|||
/// </summary>
|
||||
public static SystemInfo AmstradCPC { get; } = new SystemInfo("Amstrad CPC", CoreSystem.AmstradCPC, 2);
|
||||
|
||||
#endregion Get SystemInfo
|
||||
/// <summary>
|
||||
/// Gets the <see cref="SystemInfo"/> instance for AmstradCPC
|
||||
/// </summary>
|
||||
public static SystemInfo GGL { get; } = new SystemInfo("Game Gear Linked", CoreSystem.GGL, 2);
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="SystemInfo"/> by its <see cref="CoreSystem"/>
|
||||
/// </summary>
|
||||
/// <param name="system"><see cref="CoreSystem"/> you're looking for</param>
|
||||
/// <returns><see cref="SystemInfo"/></returns>
|
||||
public static SystemInfo FindByCoreSystem(CoreSystem system)
|
||||
#endregion Get SystemInfo
|
||||
|
||||
/// <summary>
|
||||
/// Get a <see cref="SystemInfo"/> by its <see cref="CoreSystem"/>
|
||||
/// </summary>
|
||||
/// <param name="system"><see cref="CoreSystem"/> you're looking for</param>
|
||||
/// <returns><see cref="SystemInfo"/></returns>
|
||||
public static SystemInfo FindByCoreSystem(CoreSystem system)
|
||||
{
|
||||
return _allSystemInfos.Find(s => s.System == system);
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("Couldn't load XMLGame Asset \"" + filename + "\"");
|
||||
throw new Exception($"Couldn't load XMLGame Asset \"{filename}\"");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -98,7 +98,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
catch
|
||||
{
|
||||
throw new Exception("Couldn't load XMLGame LoadAsset \"" + filename + "\"");
|
||||
throw new Exception($"Couldn't load XMLGame LoadAsset \"{filename}\"");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -363,6 +363,12 @@ namespace BizHawk.Client.Common
|
|||
public float DispCustomUserARX = -1;
|
||||
public float DispCustomUserARY = -1;
|
||||
|
||||
//these default to 0 because by default we crop nothing
|
||||
public int DispCropLeft = 0;
|
||||
public int DispCropTop = 0;
|
||||
public int DispCropRight = 0;
|
||||
public int DispCropBottom = 0;
|
||||
|
||||
// Sound options
|
||||
#if WINDOWS
|
||||
public ESoundOutputMethod SoundOutputMethod = ESoundOutputMethod.DirectSound;
|
||||
|
@ -554,6 +560,7 @@ namespace BizHawk.Client.Common
|
|||
// as this setting spans multiple cores and doesn't actually affect the behavior of any core,
|
||||
// it hasn't been absorbed into the new system
|
||||
public bool GB_AsSGB = false;
|
||||
public bool UseSubNESHawk = false;
|
||||
public bool NES_InQuickNES = true;
|
||||
public bool SNES_InSnes9x = true;
|
||||
public bool GBA_UsemGBA = true;
|
||||
|
|
|
@ -73,8 +73,8 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
|
||||
// we don't have anything for the system in question. add a set of stock paths
|
||||
var systempath = PathManager.RemoveInvalidFileSystemChars(system) + "_INTERIM";
|
||||
var systemdisp = system + " (INTERIM)";
|
||||
var systempath = $"{PathManager.RemoveInvalidFileSystemChars(system)}_INTERIM";
|
||||
var systemdisp = $"{system} (INTERIM)";
|
||||
|
||||
Paths.AddRange(new[]
|
||||
{
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace BizHawk.Client.Common
|
|||
return new Point(_wndx.Value, _wndy.Value);
|
||||
}
|
||||
|
||||
throw new InvalidOperationException("TopLeft can not be used when one of the coordinates is null");
|
||||
throw new InvalidOperationException($"{nameof(TopLeft)} can not be used when one of the coordinates is null");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
|
||||
prefix = button.GetPrecedingString("Down");
|
||||
string other = prefix + "Up";
|
||||
string other = $"{prefix}Up";
|
||||
if (Source.IsPressed(other))
|
||||
{
|
||||
if (_unpresses.Contains(button))
|
||||
|
@ -61,7 +61,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
|
||||
prefix = button.GetPrecedingString("Up");
|
||||
string other = prefix + "Down";
|
||||
string other = $"{prefix}Down";
|
||||
if (Source.IsPressed(other))
|
||||
{
|
||||
if (_unpresses.Contains(button))
|
||||
|
@ -90,7 +90,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
|
||||
prefix = button.GetPrecedingString("Right");
|
||||
string other = prefix + "Left";
|
||||
string other = $"{prefix}Left";
|
||||
if (Source.IsPressed(other))
|
||||
{
|
||||
if (_unpresses.Contains(button))
|
||||
|
@ -119,7 +119,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
|
||||
prefix = button.GetPrecedingString("Left");
|
||||
string other = prefix + "Right";
|
||||
string other = $"{prefix}Right";
|
||||
if (Source.IsPressed(other))
|
||||
{
|
||||
if (_unpresses.Contains(button))
|
||||
|
|
|
@ -93,7 +93,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
Log($"Error: {Emulator.Attributes().CoreName} does not yet implement disassemble()");
|
||||
Log($"Error: {Emulator.Attributes().CoreName} does not yet implement {nameof(IDisassemblable.Disassemble)}()");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -117,7 +117,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
Log($"Error: {Emulator.Attributes().CoreName} does not yet implement getregister()");
|
||||
Log($"Error: {Emulator.Attributes().CoreName} does not yet implement {nameof(IDebuggable.GetCpuFlagsAndRegisters)}()");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
Log($"Error: {Emulator.Attributes().CoreName} does not yet implement getregisters()");
|
||||
Log($"Error: {Emulator.Attributes().CoreName} does not yet implement {nameof(IDebuggable.GetCpuFlagsAndRegisters)}()");
|
||||
}
|
||||
|
||||
return table;
|
||||
|
@ -163,7 +163,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
Log($"Error: {Emulator.Attributes().CoreName} does not yet implement setregister()");
|
||||
Log($"Error: {Emulator.Attributes().CoreName} does not yet implement {nameof(IDebuggable.SetCpuRegister)}()");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -182,7 +182,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
catch (NotImplementedException)
|
||||
{
|
||||
Log($"Error: {Emulator.Attributes().CoreName} does not yet implement totalexecutedcycles()");
|
||||
Log($"Error: {Emulator.Attributes().CoreName} does not yet implement {nameof(IDebuggable.TotalExecutedCycles)}()");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -204,7 +204,7 @@ namespace BizHawk.Client.Common
|
|||
return InputPollableCore.IsLagFrame;
|
||||
}
|
||||
|
||||
Log($"Can not get lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable");
|
||||
Log($"Can not get lag information, {Emulator.Attributes().CoreName} does not implement {nameof(IInputPollable)}");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -218,7 +218,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
Log($"Can not set lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable");
|
||||
Log($"Can not set lag information, {Emulator.Attributes().CoreName} does not implement {nameof(IInputPollable)}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -231,7 +231,7 @@ namespace BizHawk.Client.Common
|
|||
return InputPollableCore.LagCount;
|
||||
}
|
||||
|
||||
Log($"Can not get lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable");
|
||||
Log($"Can not get lag information, {Emulator.Attributes().CoreName} does not implement {nameof(IInputPollable)}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -245,7 +245,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
Log($"Can not set lag information, {Emulator.Attributes().CoreName} does not implement IInputPollable");
|
||||
Log($"Can not set lag information, {Emulator.Attributes().CoreName} does not implement {nameof(IInputPollable)}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -62,10 +62,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log(
|
||||
"error running function attached by lua function event.onsavestate" +
|
||||
"\nError message: " +
|
||||
e.Message);
|
||||
Log($"error running function attached by lua function event.onsavestate\nError message: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,10 +81,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log(
|
||||
"error running function attached by lua function event.onloadstate" +
|
||||
"\nError message: " +
|
||||
e.Message);
|
||||
Log($"error running function attached by lua function event.onloadstate\nError message: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -106,10 +100,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log(
|
||||
"error running function attached by lua function event.onframestart" +
|
||||
"\nError message: " +
|
||||
e.Message);
|
||||
Log($"error running function attached by lua function event.onframestart\nError message: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -128,10 +119,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log(
|
||||
"error running function attached by lua function event.onframeend" +
|
||||
"\nError message: " +
|
||||
e.Message);
|
||||
Log($"error running function attached by lua function event.onframeend\nError message: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ namespace BizHawk.Client.Common
|
|||
public override string Name => "gameinfo";
|
||||
|
||||
[LuaMethodExample("local stgamget = gameinfo.getromname( );")]
|
||||
[LuaMethod("getromname", "returns the path of the currently loaded rom, if a rom is loaded")]
|
||||
[LuaMethod("getromname", "returns the name of the currently loaded rom, if a rom is loaded")]
|
||||
public string GetRomName()
|
||||
{
|
||||
if (Global.Game != null)
|
||||
|
|
|
@ -25,9 +25,9 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
buttons[button] = adaptor.IsPressed(button);
|
||||
}
|
||||
else if (button.Length >= 3 && button.Substring(0, 2) == "P" + controller)
|
||||
else if (button.Length >= 3 && button.Substring(0, 2) == $"P{controller}")
|
||||
{
|
||||
buttons[button.Substring(3)] = adaptor.IsPressed("P" + controller + " " + button.Substring(3));
|
||||
buttons[button.Substring(3)] = adaptor.IsPressed($"P{controller} {button.Substring(3)}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -37,9 +37,9 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
buttons[button] = adaptor.GetFloat(button);
|
||||
}
|
||||
else if (button.Length >= 3 && button.Substring(0, 2) == "P" + controller)
|
||||
else if (button.Length >= 3 && button.Substring(0, 2) == $"P{controller}")
|
||||
{
|
||||
buttons[button.Substring(3)] = adaptor.GetFloat("P" + controller + " " + button.Substring(3));
|
||||
buttons[button.Substring(3)] = adaptor.GetFloat($"P{controller} {button.Substring(3)}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -85,7 +85,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Log("invalid mnemonic string: " + inputLogEntry);
|
||||
Log($"invalid mnemonic string: {inputLogEntry}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ namespace BizHawk.Client.Common
|
|||
var toPress = button.ToString();
|
||||
if (controller.HasValue)
|
||||
{
|
||||
toPress = "P" + controller + " " + button;
|
||||
toPress = $"P{controller} {button}";
|
||||
}
|
||||
|
||||
if (!invert)
|
||||
|
@ -180,7 +180,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
Global.StickyXORAdapter.SetFloat("P" + controller + " " + name, theValue);
|
||||
Global.StickyXORAdapter.SetFloat($"P{controller} {name}", theValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -149,7 +149,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (!string.IsNullOrEmpty(filename))
|
||||
{
|
||||
filename += "." + Global.MovieSession.Movie.PreferredExtension;
|
||||
filename += $".{Global.MovieSession.Movie.PreferredExtension}";
|
||||
var test = new FileInfo(filename);
|
||||
if (test.Exists)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
@ -106,7 +105,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
var table = Lua.NewTable();
|
||||
m_dbConnection.Open();
|
||||
string sql = "PRAGMA read_uncommitted =1;" + query;
|
||||
string sql = $"PRAGMA read_uncommitted =1;{query}";
|
||||
SQLiteCommand command = new SQLiteCommand(sql, m_dbConnection);
|
||||
SQLiteDataReader reader = command.ExecuteReader();
|
||||
bool rows = reader.HasRows;
|
||||
|
@ -120,7 +119,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
for (int i = 0; i < reader.FieldCount; ++i)
|
||||
{
|
||||
table[columns[i] + " " + rowCount.ToString()] = reader.GetValue(i);
|
||||
table[$"{columns[i]} {rowCount}"] = reader.GetValue(i);
|
||||
}
|
||||
rowCount += 1;
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace BizHawk.Client.Common
|
|||
var hex = $"{num:X}";
|
||||
if (hex.Length == 1)
|
||||
{
|
||||
hex = "0" + hex;
|
||||
hex = $"0{hex}";
|
||||
}
|
||||
|
||||
return hex;
|
||||
|
@ -46,7 +46,7 @@ namespace BizHawk.Client.Common
|
|||
var octal = Convert.ToString(num, 8);
|
||||
if (octal.Length == 1)
|
||||
{
|
||||
octal = "0" + octal;
|
||||
octal = $"0{octal}";
|
||||
}
|
||||
|
||||
return octal;
|
||||
|
|
|
@ -26,10 +26,10 @@ __Types and notation__
|
|||
* ? (question mark)
|
||||
** A question mark next to a value indicates that it is a Nullable type (only applies to types that are not normally nullable)
|
||||
* [[]] (brackets)
|
||||
** Brackets around a parameter indicate that the parameter is optional. optional parameters have an equals sign followed by the value that will be used if no value is supplied.
|
||||
** Brackets around a parameter indicate that the parameter is optional. Optional parameters have an equals sign followed by the value that will be used if no value is supplied.
|
||||
** Brackets after a parameter type indicate it is an array
|
||||
* null
|
||||
** null is equivalent to the lua nil
|
||||
** null is equivalent to the lua nil. Lua doesn't support named arguments, it checks the arguments by position. So if you're sending an optional argument that goes ''after'' other optional arguments you don't want to send, replace those with lua nil.
|
||||
* Color
|
||||
** This is a .NET System.Drawing.Color struct. The value passed from lua is any value acceptable in the Color constructor. This means either a string with the color name such as ""red"", or a 0xAARRGGBB integer value. Unless specified, this is not a nullable value
|
||||
* object
|
||||
|
@ -102,7 +102,7 @@ __Types and notation__
|
|||
{
|
||||
var completion = new SublimeCompletions.Completion
|
||||
{
|
||||
Trigger = f.Library + "." + f.Name
|
||||
Trigger = $"{f.Library}.{f.Name}"
|
||||
};
|
||||
|
||||
var sb = new StringBuilder();
|
||||
|
|
|
@ -101,7 +101,7 @@ namespace BizHawk.Client.Common
|
|||
foreach (var method in methods)
|
||||
{
|
||||
var luaMethodAttr = (LuaMethodAttribute)method.GetCustomAttributes(luaAttr, false).First();
|
||||
var luaName = Name + "." + luaMethodAttr.Name;
|
||||
var luaName = $"{Name}.{luaMethodAttr.Name}";
|
||||
Lua.RegisterFunction(luaName, this, method);
|
||||
|
||||
docs?.Add(new LibraryFunction(Name, callingLibrary.Description(), method));
|
||||
|
|
|
@ -67,8 +67,7 @@ namespace BizHawk.Client.Common
|
|||
return d.PeekByte(addr);
|
||||
}
|
||||
|
||||
Log("Warning: attempted read of " + addr +
|
||||
" outside the memory size of " + d.Size);
|
||||
Log($"Warning: attempted read of {addr} outside the memory size of {d.Size}");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -83,8 +82,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
Log("Warning: attempted write to " + addr +
|
||||
" outside the memory size of " + d.Size);
|
||||
Log($"Warning: attempted write to {addr} outside the memory size of {d.Size}");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -188,8 +186,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
Log("Warning: Attempted read " + lastAddr + " outside memory domain size of " +
|
||||
d.Size + " in readbyterange()");
|
||||
Log($"Warning: Attempted read {lastAddr} outside memory domain size of {d.Size} in readbyterange()");
|
||||
}
|
||||
|
||||
return table;
|
||||
|
@ -209,8 +206,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
Log("Warning: Attempted write " + addr + " outside memory domain size of " +
|
||||
d.Size + " in writebyterange()");
|
||||
Log($"Warning: Attempted write {addr} outside memory domain size of {d.Size} in writebyterange()");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -230,8 +226,7 @@ namespace BizHawk.Client.Common
|
|||
return BitConverter.ToSingle(bytes, 0);
|
||||
}
|
||||
|
||||
Log("Warning: Attempted read " + addr +
|
||||
" outside memory size of " + d.Size);
|
||||
Log($"Warning: Attempted read {addr} outside memory size of {d.Size}");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -250,8 +245,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
Log("Warning: Attempted write " + addr +
|
||||
" outside memory size of " + d.Size);
|
||||
Log($"Warning: Attempted write {addr} outside memory size of {d.Size}");
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -27,7 +27,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
private bool CoolSetCurrentDirectory(string path, string currDirSpeedHack = null)
|
||||
{
|
||||
string target = _currentDirectory + "\\";
|
||||
string target = $"{_currentDirectory}\\";
|
||||
|
||||
// first we'll bypass it with a general hack: dont do any setting if the value's already there (even at the OS level, setting the directory can be slow)
|
||||
// yeah I know, not the smoothest move to compare strings here, in case path normalization is happening at some point
|
||||
|
@ -45,7 +45,7 @@ namespace BizHawk.Client.Common
|
|||
// WARNING: setting the current directory is SLOW!!! security checks for some reason.
|
||||
// so we're bypassing it with windows hacks
|
||||
#if WINDOWS
|
||||
fixed (byte* pstr = &System.Text.Encoding.Unicode.GetBytes(target + "\0")[0])
|
||||
fixed (byte* pstr = &System.Text.Encoding.Unicode.GetBytes($"{target}\0")[0])
|
||||
return SetCurrentDirectoryW(pstr);
|
||||
#else
|
||||
if (System.IO.Directory.Exists(CurrentDirectory)) // race condition for great justice
|
||||
|
|
|
@ -23,11 +23,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logCallback(
|
||||
"error running function attached by the event " +
|
||||
Event +
|
||||
"\nError message: " +
|
||||
ex.Message);
|
||||
logCallback($"error running function attached by the event {Event}\nError message: {ex.Message}");
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -201,7 +201,7 @@ namespace BizHawk.Client.Common
|
|||
var result = Movie.Stop(saveChanges);
|
||||
if (result)
|
||||
{
|
||||
Output(Path.GetFileName(Movie.Filename) + " written to disk.");
|
||||
Output($"{Path.GetFileName(Movie.Filename)} written to disk.");
|
||||
}
|
||||
|
||||
Output(message);
|
||||
|
@ -225,7 +225,7 @@ namespace BizHawk.Client.Common
|
|||
if (Movie.IsPlaying)
|
||||
{
|
||||
Movie.ClearFrame(Global.Emulator.Frame);
|
||||
Output("Scrubbed input at frame " + Global.Emulator.Frame);
|
||||
Output($"Scrubbed input at frame {Global.Emulator.Frame}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace BizHawk.Client.Common
|
|||
return "Recording None";
|
||||
}
|
||||
|
||||
return "Recording Player " + CurrentPlayer;
|
||||
return $"Recording Player {CurrentPlayer}";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -59,19 +59,9 @@ namespace BizHawk.Client.Common
|
|||
int startTime = (int)(start * 1000 / fps);
|
||||
int endTime = (int)(end * 1000 / fps);
|
||||
|
||||
var startString = string.Format(
|
||||
"{0:d2}:{1:d2}:{2:d2},{3:d3}",
|
||||
startTime / 3600000,
|
||||
(startTime / 60000) % 60,
|
||||
(startTime / 1000) % 60,
|
||||
startTime % 1000);
|
||||
var startString = $"{startTime / 3600000:d2}:{(startTime / 60000) % 60:d2}:{(startTime / 1000) % 60:d2},{startTime % 1000:d3}";
|
||||
|
||||
var endString = string.Format(
|
||||
"{0:d2}:{1:d2}:{2:d2},{3:d3}",
|
||||
endTime / 3600000,
|
||||
(endTime / 60000) % 60,
|
||||
(endTime / 1000) % 60,
|
||||
endTime % 1000);
|
||||
var endString = $"{endTime / 3600000:d2}:{(endTime / 60000) % 60:d2}:{(endTime / 1000) % 60:d2},{endTime % 1000:d3}";
|
||||
|
||||
sb.Append(startString);
|
||||
sb.Append(" --> ");
|
||||
|
|
|
@ -103,7 +103,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (i > 0 && lastframe == subs[i].Frame)
|
||||
{
|
||||
subs[i].Message = subs[i - 1].Message + " " + subs[i].Message;
|
||||
subs[i].Message = $"{subs[i - 1].Message} {subs[i].Message}";
|
||||
subs.Remove(subs[i - 1]);
|
||||
i--;
|
||||
}
|
||||
|
|
|
@ -166,6 +166,12 @@ namespace BizHawk.Client.Common
|
|||
|
||||
protected virtual void Write(string fn, bool backup = false)
|
||||
{
|
||||
if (Global.Emulator is BizHawk.Emulation.Cores.Nintendo.SubNESHawk.SubNESHawk)
|
||||
{
|
||||
var _subnes = (BizHawk.Emulation.Cores.Nintendo.SubNESHawk.SubNESHawk)Global.Emulator;
|
||||
Header["VBlankCount"] = _subnes.VBL_CNT.ToString();
|
||||
}
|
||||
|
||||
var file = new FileInfo(fn);
|
||||
if (!file.Directory.Exists)
|
||||
{
|
||||
|
|
|
@ -250,10 +250,7 @@ namespace BizHawk.Client.Common
|
|||
return true;
|
||||
}
|
||||
|
||||
errorMessage = "The savestate is from frame "
|
||||
+ newLog.Count
|
||||
+ " which is greater than the current movie length of "
|
||||
+ Log.Count;
|
||||
errorMessage = $"The savestate is from frame {newLog.Count} which is greater than the current movie length of {Log.Count}";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -262,9 +259,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
if (Log[i] != newLog[i])
|
||||
{
|
||||
errorMessage = "The savestate input does not match the movie input at frame "
|
||||
+ (i + 1)
|
||||
+ ".";
|
||||
errorMessage = $"The savestate input does not match the movie input at frame {(i + 1)}.";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -253,7 +253,7 @@ namespace BizHawk.Client.Common
|
|||
string prefix = "";
|
||||
if (ControlType != "Gameboy Controller" && ControlType != "TI83 Controller")
|
||||
{
|
||||
prefix = "P" + player + " ";
|
||||
prefix = $"P{player} ";
|
||||
}
|
||||
|
||||
foreach (string button in BkmMnemonicConstants.Buttons[ControlType].Keys)
|
||||
|
@ -352,7 +352,7 @@ namespace BizHawk.Client.Common
|
|||
int start = 3;
|
||||
foreach (string button in BkmMnemonicConstants.Buttons[ControlType].Keys)
|
||||
{
|
||||
Force("P" + player + " " + button, c[srcindex + start++]);
|
||||
Force($"P{player} {button}", c[srcindex + start++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -393,7 +393,7 @@ namespace BizHawk.Client.Common
|
|||
int start = 3;
|
||||
foreach (string button in BkmMnemonicConstants.Buttons["GPGX 3-Button Controller"].Keys)
|
||||
{
|
||||
Force("P" + player + " " + button, c[srcindex + start++]);
|
||||
Force($"P{player} {button}", c[srcindex + start++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -429,7 +429,7 @@ namespace BizHawk.Client.Common
|
|||
int start = 3;
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[ControlType].Keys)
|
||||
{
|
||||
Force("P" + player + " " + button, c[srcindex + start++]);
|
||||
Force($"P{player} {button}", c[srcindex + start++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -497,12 +497,12 @@ namespace BizHawk.Client.Common
|
|||
int start = 3;
|
||||
foreach (string button in BkmMnemonicConstants.Buttons[ControlType].Keys)
|
||||
{
|
||||
Force("P" + player + " " + button, c[srcindex + start++]);
|
||||
Force($"P{player} {button}", c[srcindex + start++]);
|
||||
}
|
||||
|
||||
foreach (string name in BkmMnemonicConstants.Analogs[ControlType].Keys)
|
||||
{
|
||||
Force("P" + player + " " + name, int.Parse(mnemonic.Substring(srcindex + start, 4)));
|
||||
Force($"P{player} {name}", int.Parse(mnemonic.Substring(srcindex + start, 4)));
|
||||
start += 5;
|
||||
}
|
||||
}
|
||||
|
@ -539,7 +539,7 @@ namespace BizHawk.Client.Common
|
|||
int start = 3;
|
||||
foreach (string button in BkmMnemonicConstants.Buttons[ControlType].Keys)
|
||||
{
|
||||
Force("P" + player + " " + button, c[srcindex + start++]);
|
||||
Force($"P{player} {button}", c[srcindex + start++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -585,7 +585,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
foreach (string button in BkmMnemonicConstants.Buttons[ControlType].Keys)
|
||||
{
|
||||
Force("P" + player + " " + button, c[srcindex + start++]);
|
||||
Force($"P{player} {button}", c[srcindex + start++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -635,7 +635,7 @@ namespace BizHawk.Client.Common
|
|||
int start = 1;
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[ControlType].Keys)
|
||||
{
|
||||
Force("P" + player + " " + button, c[srcindex + start++]);
|
||||
Force($"P{player} {button}", c[srcindex + start++]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -165,7 +165,7 @@ namespace BizHawk.Client.Common
|
|||
var prefix = "";
|
||||
if (_controlType != "Gameboy Controller" && _controlType != "TI83 Controller")
|
||||
{
|
||||
prefix = "P" + player + " ";
|
||||
prefix = $"P{player} ";
|
||||
}
|
||||
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
|
@ -313,7 +313,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed("P" + player + " " + button) ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
|
@ -330,7 +330,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed("P" + player + " " + button) ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append('|');
|
||||
|
@ -398,7 +398,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed("P" + player + " " + button) ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append('|');
|
||||
|
@ -448,7 +448,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed("P" + player + " " + button) ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
if (BkmMnemonicConstants.Analogs[_controlType].Keys.Count > 0)
|
||||
|
@ -460,37 +460,37 @@ namespace BizHawk.Client.Common
|
|||
// Nasty hackery
|
||||
if (name == "Y Axis")
|
||||
{
|
||||
if (IsBasePressed("P" + player + " A Up"))
|
||||
if (IsBasePressed($"P{player} A Up"))
|
||||
{
|
||||
val = 127;
|
||||
}
|
||||
else if (IsBasePressed("P" + player + " A Down"))
|
||||
else if (IsBasePressed($"P{player} A Down"))
|
||||
{
|
||||
val = -127;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (int)GetBaseFloat("P" + player + " " + name);
|
||||
val = (int)GetBaseFloat($"P{player} {name}");
|
||||
}
|
||||
}
|
||||
else if (name == "X Axis")
|
||||
{
|
||||
if (IsBasePressed("P" + player + " A Left"))
|
||||
if (IsBasePressed($"P{player} A Left"))
|
||||
{
|
||||
val = -127;
|
||||
}
|
||||
else if (IsBasePressed("P" + player + " A Right"))
|
||||
else if (IsBasePressed($"P{player} A Right"))
|
||||
{
|
||||
val = 127;
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (int)GetBaseFloat("P" + player + " " + name);
|
||||
val = (int)GetBaseFloat($"P{player} {name}");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
val = (int)GetBaseFloat("P" + player + " " + name);
|
||||
val = (int)GetBaseFloat($"P{player} {name}");
|
||||
}
|
||||
|
||||
if (val >= 0)
|
||||
|
@ -532,7 +532,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed("P" + player + " " + button) ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append('|');
|
||||
|
@ -563,7 +563,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed("P" + player + " " + button) ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
|
@ -595,7 +595,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
foreach (var button in BkmMnemonicConstants.Buttons[_controlType].Keys)
|
||||
{
|
||||
input.Append(IsBasePressed("P" + player + " " + button) ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
input.Append(IsBasePressed($"P{player} {button}") ? BkmMnemonicConstants.Buttons[_controlType][button] : ".");
|
||||
}
|
||||
|
||||
input.Append("|");
|
||||
|
|
|
@ -265,7 +265,7 @@ namespace BizHawk.Client.Common
|
|||
// TODO: clean this up
|
||||
if (_loopOffset.HasValue)
|
||||
{
|
||||
sw.WriteLine("LoopOffset " + _loopOffset);
|
||||
sw.WriteLine($"LoopOffset {_loopOffset}");
|
||||
}
|
||||
|
||||
foreach (var input in _log)
|
||||
|
|
|
@ -254,10 +254,7 @@ namespace BizHawk.Client.Common
|
|||
return true;
|
||||
}
|
||||
|
||||
errorMessage = "The savestate is from frame "
|
||||
+ log.Count
|
||||
+ " which is greater than the current movie length of "
|
||||
+ _log.Count;
|
||||
errorMessage = $"The savestate is from frame {log.Count} which is greater than the current movie length of {_log.Count}";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
@ -266,9 +263,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
if (_log[i] != log[i])
|
||||
{
|
||||
errorMessage = "The savestate input does not match the movie input at frame "
|
||||
+ (i + 1)
|
||||
+ ".";
|
||||
errorMessage = $"The savestate input does not match the movie input at frame {(i + 1)}.";
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ using System.Linq;
|
|||
|
||||
using BizHawk.Emulation.Common;
|
||||
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
|
||||
using BizHawk.Emulation.Cores.Nintendo.SubNESHawk;
|
||||
using BizHawk.Emulation.Cores.Sega.MasterSystem;
|
||||
using BizHawk.Emulation.Common.IEmulatorExtensions;
|
||||
using BizHawk.Emulation.Cores.Consoles.Sega.gpgx;
|
||||
|
@ -15,7 +16,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
|
|||
{
|
||||
public static TasMovie ToTasMovie(this IMovie old, bool copy = false)
|
||||
{
|
||||
string newFilename = old.Filename + "." + TasMovie.Extension;
|
||||
string newFilename = $"{old.Filename}.{TasMovie.Extension}";
|
||||
|
||||
if (File.Exists(newFilename))
|
||||
{
|
||||
|
@ -25,7 +26,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
|
|||
{
|
||||
if (File.Exists(newFilename))
|
||||
{
|
||||
newFilename = old.Filename + " (" + fileNum + ")" + "." + TasMovie.Extension;
|
||||
newFilename = $"{old.Filename} ({fileNum}).{TasMovie.Extension}";
|
||||
fileNum++;
|
||||
}
|
||||
else
|
||||
|
@ -125,7 +126,17 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
|
|||
|
||||
public static TasMovie ConvertToSavestateAnchoredMovie(this TasMovie old, int frame, byte[] savestate)
|
||||
{
|
||||
string newFilename = old.Filename + "." + TasMovie.Extension;
|
||||
string newFilename = old.Filename;
|
||||
|
||||
if (old.Filename.Contains("tasproj"))
|
||||
{
|
||||
newFilename = newFilename.Remove(newFilename.Length - 7, 7);
|
||||
newFilename = $"{newFilename}nfn.{TasMovie.Extension}";
|
||||
}
|
||||
else
|
||||
{
|
||||
newFilename = $"{old.Filename}.{TasMovie.Extension}";
|
||||
}
|
||||
|
||||
if (File.Exists(newFilename))
|
||||
{
|
||||
|
@ -135,7 +146,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
|
|||
{
|
||||
if (File.Exists(newFilename))
|
||||
{
|
||||
newFilename = old.Filename + " (" + fileNum + ")" + "." + TasMovie.Extension;
|
||||
newFilename = $"{old.Filename} ({fileNum}).{TasMovie.Extension}";
|
||||
fileNum++;
|
||||
}
|
||||
else
|
||||
|
@ -200,7 +211,17 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
|
|||
|
||||
public static TasMovie ConvertToSaveRamAnchoredMovie(this TasMovie old, byte[] saveRam)
|
||||
{
|
||||
string newFilename = old.Filename + "." + TasMovie.Extension;
|
||||
string newFilename = old.Filename;
|
||||
|
||||
if (old.Filename.Contains("tasproj"))
|
||||
{
|
||||
newFilename = newFilename.Remove(newFilename.Length - 7, 7);
|
||||
newFilename = $"{newFilename}nfsr.{TasMovie.Extension}";
|
||||
}
|
||||
else
|
||||
{
|
||||
newFilename = $"{old.Filename}.{TasMovie.Extension}";
|
||||
}
|
||||
|
||||
if (File.Exists(newFilename))
|
||||
{
|
||||
|
@ -210,7 +231,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
|
|||
{
|
||||
if (File.Exists(newFilename))
|
||||
{
|
||||
newFilename = old.Filename + " (" + fileNum + ")" + "." + TasMovie.Extension;
|
||||
newFilename = $"{old.Filename} ({fileNum}).{TasMovie.Extension}";
|
||||
fileNum++;
|
||||
}
|
||||
else
|
||||
|
@ -302,7 +323,7 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
|
|||
{
|
||||
foreach (var firmware in Global.FirmwareManager.RecentlyServed)
|
||||
{
|
||||
var key = firmware.SystemId + "_Firmware_" + firmware.FirmwareId;
|
||||
var key = $"{firmware.SystemId}_Firmware_{firmware.FirmwareId}";
|
||||
|
||||
if (!movie.HeaderEntries.ContainsKey(key))
|
||||
{
|
||||
|
@ -336,6 +357,11 @@ namespace BizHawk.Client.Common.MovieConversionExtensions
|
|||
movie.HeaderEntries.Add("Is32X", "1");
|
||||
}
|
||||
|
||||
if (Global.Emulator is SubNESHawk)
|
||||
{
|
||||
movie.HeaderEntries.Add("VBlankCount", "0");
|
||||
}
|
||||
|
||||
movie.Core = ((CoreAttribute)Attribute
|
||||
.GetCustomAttribute(Global.Emulator.GetType(), typeof(CoreAttribute)))
|
||||
.CoreName;
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
Result.Movie.Comments.Add(Movieorigin + " .fm2 version 3");
|
||||
Result.Movie.Comments.Add($"{Movieorigin} .fm2 version 3");
|
||||
}
|
||||
}
|
||||
else if (line.ToLower().StartsWith("romfilename"))
|
||||
|
@ -139,7 +139,7 @@ namespace BizHawk.Client.Common
|
|||
string length = line.Substring(first + 1, second - first - 1);
|
||||
string message = line.Substring(second + 1).Trim();
|
||||
|
||||
return "subtitle " + frame + " 0 0 " + length + " FFFFFFFF " + message;
|
||||
return $"subtitle {frame} 0 0 {length} FFFFFFFF {message}";
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -41,7 +41,7 @@ namespace BizHawk.Client.Common
|
|||
return Result;
|
||||
}
|
||||
|
||||
var newFileName = SourceFile.FullName + "." + Bk2Movie.Extension;
|
||||
var newFileName = $"{SourceFile.FullName}.{Bk2Movie.Extension}";
|
||||
Result.Movie = new Bk2Movie(newFileName);
|
||||
|
||||
RunImport();
|
||||
|
|
|
@ -57,7 +57,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
messageCallback(Path.GetFileName(fn) + " imported as " + m.Filename);
|
||||
messageCallback($"{Path.GetFileName(fn)} imported as {m.Filename}");
|
||||
}
|
||||
|
||||
if (!Directory.Exists(d))
|
||||
|
@ -83,7 +83,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (importerType == default(Type))
|
||||
{
|
||||
errorMsg = "No importer found for file type " + ext;
|
||||
errorMsg = $"No importer found for file type {ext}";
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -205,7 +205,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (m != null)
|
||||
{
|
||||
m.Filename += "." + BkmMovie.Extension;
|
||||
m.Filename += $".{BkmMovie.Extension}";
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -230,7 +230,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
"BKM", "FCM", "FM2", "FMV", "GMV", "MCM", "MC2", "MMV", "NMV", "LSMV", "SMV", "VBM", "VMV", "YMV", "ZMV"
|
||||
};
|
||||
return extensions.Any(ext => extension.ToUpper() == "." + ext);
|
||||
return extensions.Any(ext => extension.ToUpper() == $".{ext}");
|
||||
}
|
||||
|
||||
// Reduce all whitespace to single spaces.
|
||||
|
@ -261,7 +261,7 @@ namespace BizHawk.Client.Common
|
|||
for (int section = 2; section < sections.Length - 1; section++)
|
||||
{
|
||||
int player = section - 1; // We start with 1
|
||||
string prefix = "P" + player + " "; // "P1"
|
||||
string prefix = $"P{player} "; // "P1"
|
||||
|
||||
for (int button = 0; button < buttons.Length; button++)
|
||||
{
|
||||
|
@ -344,7 +344,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (warningMsg != "")
|
||||
{
|
||||
warningMsg = "Unable to import " + warningMsg + " command on line " + lineNum + ".";
|
||||
warningMsg = $"Unable to import {warningMsg} command on line {lineNum}.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -397,7 +397,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
// The player number is one less than the section number for the reasons explained above.
|
||||
int player = section + playerOffset;
|
||||
string prefix = "P" + player + " ";
|
||||
string prefix = $"P{player} ";
|
||||
|
||||
// Gameboy doesn't currently have a prefix saying which player the input is for.
|
||||
if (controllers.Definition.Name == "Gameboy Controller")
|
||||
|
@ -450,7 +450,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
|
||||
string message = line.Substring(second + 1).Trim();
|
||||
m.Subtitles.AddFromString("subtitle " + frame + " 0 0 " + length + " FFFFFFFF " + message);
|
||||
m.Subtitles.AddFromString($"subtitle {frame} 0 0 {length} FFFFFFFF {message}");
|
||||
}
|
||||
|
||||
return m;
|
||||
|
@ -507,14 +507,12 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else if (line.ToLower().StartsWith("emuversion"))
|
||||
{
|
||||
m.Comments.Add(
|
||||
EMULATIONORIGIN + " " + emulator + " version " + ParseHeader(line, "emuVersion"));
|
||||
m.Comments.Add($"{EMULATIONORIGIN} {emulator} version {ParseHeader(line, "emuVersion")}");
|
||||
}
|
||||
else if (line.ToLower().StartsWith("version"))
|
||||
{
|
||||
string version = ParseHeader(line, "version");
|
||||
m.Comments.Add(
|
||||
MOVIEORIGIN + " " + Path.GetExtension(path) + " version " + version);
|
||||
m.Comments.Add($"{MOVIEORIGIN} {Path.GetExtension(path)} version {version}");
|
||||
if (Path.GetExtension(path).ToUpper() == ".FM2" && version != "3")
|
||||
{
|
||||
errorMsg = ".FM2 movie version must always be 3.";
|
||||
|
@ -683,7 +681,7 @@ namespace BizHawk.Client.Common
|
|||
return null;
|
||||
}
|
||||
|
||||
m.Comments.Add(MOVIEORIGIN + " .FCM version " + version);
|
||||
m.Comments.Add($"{MOVIEORIGIN} .FCM version {version}");
|
||||
|
||||
// 008 1-byte flags
|
||||
byte flags = r.ReadByte();
|
||||
|
@ -715,7 +713,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
// other: reserved, set to 0
|
||||
bool syncHack = ((flags >> 4) & 0x1) != 0;
|
||||
m.Comments.Add(SYNCHACK + " " + syncHack);
|
||||
m.Comments.Add($"{SYNCHACK} {syncHack}");
|
||||
|
||||
// 009 1-byte flags: reserved, set to 0
|
||||
r.ReadByte();
|
||||
|
@ -749,7 +747,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
// 030 4-byte little-endian unsigned int: version of the emulator used
|
||||
uint emuVersion = r.ReadUInt32();
|
||||
m.Comments.Add(EMULATIONORIGIN + " FCEU " + emuVersion);
|
||||
m.Comments.Add($"{EMULATIONORIGIN} FCEU {emuVersion}");
|
||||
|
||||
// 034 name of the ROM used - UTF8 encoded nul-terminated string.
|
||||
List<byte> gameBytes = new List<byte>();
|
||||
|
@ -870,7 +868,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (warningMsg != "")
|
||||
{
|
||||
warningMsg = "Unable to import " + warningMsg + " command at frame " + frame + ".";
|
||||
warningMsg = $"Unable to import {warningMsg} command at frame {frame}.";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -917,7 +915,7 @@ namespace BizHawk.Client.Common
|
|||
The controller update toggles the affected input. Controller update data is emitted to the movie file
|
||||
only when the state of the controller changes.
|
||||
*/
|
||||
controllers["P" + player + " " + buttons[button]] = !controllers["P" + player + " " + buttons[button]];
|
||||
controllers[$"P{player} {buttons[button]}"] = !controllers[$"P{player} {buttons[button]}"];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1012,12 +1010,12 @@ namespace BizHawk.Client.Common
|
|||
|
||||
// 010 64-byte zero-terminated emulator identifier string
|
||||
string emuVersion = NullTerminated(r.ReadStringFixedAscii(64));
|
||||
m.Comments.Add(EMULATIONORIGIN + " Famtasia version " + emuVersion);
|
||||
m.Comments.Add(MOVIEORIGIN + " .FMV");
|
||||
m.Comments.Add($"{EMULATIONORIGIN} Famtasia version {emuVersion}");
|
||||
m.Comments.Add($"{MOVIEORIGIN} .FMV");
|
||||
|
||||
// 050 64-byte zero-terminated movie title string
|
||||
string description = NullTerminated(r.ReadStringFixedAscii(64));
|
||||
m.Comments.Add(COMMENT + " " + description);
|
||||
m.Comments.Add($"{COMMENT} {description}");
|
||||
if (!controller1 && !controller2 && !fds)
|
||||
{
|
||||
warningMsg = "No input recorded.";
|
||||
|
@ -1080,7 +1078,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
for (int button = 0; button < buttons.Length; button++)
|
||||
{
|
||||
controllers["P" + player + " " + buttons[button]] = ((controllerState >> button) & 0x1) != 0;
|
||||
controllers[$"P{player} {buttons[button]}"] = ((controllerState >> button) & 0x1) != 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1119,8 +1117,8 @@ namespace BizHawk.Client.Common
|
|||
|
||||
// 00F ASCII-encoded GMV file format version. The most recent is 'A'. (?)
|
||||
string version = r.ReadStringFixedAscii(1);
|
||||
m.Comments.Add(MOVIEORIGIN + " .GMV version " + version);
|
||||
m.Comments.Add(EMULATIONORIGIN + " Gens");
|
||||
m.Comments.Add($"{MOVIEORIGIN} .GMV version {version}");
|
||||
m.Comments.Add($"{EMULATIONORIGIN} Gens");
|
||||
|
||||
// 010 4-byte little-endian unsigned int: rerecord count
|
||||
uint rerecordCount = r.ReadUInt32();
|
||||
|
@ -1169,7 +1167,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
// 018 40-byte zero-terminated ASCII movie name string
|
||||
string description = NullTerminated(r.ReadStringFixedAscii(40));
|
||||
m.Comments.Add(COMMENT + " " + description);
|
||||
m.Comments.Add($"{COMMENT} {description}");
|
||||
|
||||
/*
|
||||
040 frame data
|
||||
|
@ -1213,7 +1211,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
for (int button = 0; button < buttons.Length; button++)
|
||||
{
|
||||
controllers["P" + player + " " + buttons[button]] = ((controllerState >> button) & 0x1) == 0;
|
||||
controllers[$"P{player} {buttons[button]}"] = ((controllerState >> button) & 0x1) == 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -1222,12 +1220,12 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
if (player1Config == "6")
|
||||
{
|
||||
controllers["P1 " + other[button]] = ((controllerState >> button) & 0x1) == 0;
|
||||
controllers[$"P1 {other[button]}"] = ((controllerState >> button) & 0x1) == 0;
|
||||
}
|
||||
|
||||
if (player2Config == "6")
|
||||
{
|
||||
controllers["P2 " + other[button]] = ((controllerState >> (button + 4)) & 0x1) == 0;
|
||||
controllers[$"P2 {other[button]}"] = ((controllerState >> (button + 4)) & 0x1) == 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1275,7 +1273,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
if (authorLast != "")
|
||||
{
|
||||
authorList += authorLast + ", ";
|
||||
authorList += $"{authorLast}, ";
|
||||
}
|
||||
|
||||
authorLast = author;
|
||||
|
@ -1301,7 +1299,7 @@ namespace BizHawk.Client.Common
|
|||
hf.BindArchiveMember(item.Index);
|
||||
var stream = hf.GetStream();
|
||||
string coreversion = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim();
|
||||
m.Comments.Add(COREORIGIN + " " + coreversion);
|
||||
m.Comments.Add($"{COREORIGIN} {coreversion}");
|
||||
hf.Unbind();
|
||||
}
|
||||
else if (item.Name == "gamename")
|
||||
|
@ -1446,7 +1444,7 @@ namespace BizHawk.Client.Common
|
|||
string rom = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim();
|
||||
int pos = item.Name.LastIndexOf(".sha256");
|
||||
string name = item.Name.Substring(0, pos);
|
||||
m.Header[SHA256 + "_" + name] = rom;
|
||||
m.Header[$"{SHA256}_{name}"] = rom;
|
||||
hf.Unbind();
|
||||
}
|
||||
else if (item.Name == "savestate")
|
||||
|
@ -1491,7 +1489,7 @@ namespace BizHawk.Client.Common
|
|||
hf.BindArchiveMember(item.Index);
|
||||
var stream = hf.GetStream();
|
||||
string systemid = Encoding.UTF8.GetString(stream.ReadAllBytes()).Trim();
|
||||
m.Comments.Add(EMULATIONORIGIN + " " + systemid);
|
||||
m.Comments.Add($"{EMULATIONORIGIN} {systemid}");
|
||||
hf.Unbind();
|
||||
}
|
||||
}
|
||||
|
@ -1528,11 +1526,11 @@ namespace BizHawk.Client.Common
|
|||
|
||||
// 008 uint32 Mednafen Version (Current is 0A 08)
|
||||
uint emuVersion = r.ReadUInt32();
|
||||
m.Comments.Add(EMULATIONORIGIN + " Mednafen " + emuVersion);
|
||||
m.Comments.Add($"{EMULATIONORIGIN} Mednafen {emuVersion}");
|
||||
|
||||
// 00C uint32 Movie Format Version (Current is 01)
|
||||
uint version = r.ReadUInt32();
|
||||
m.Comments.Add(MOVIEORIGIN + " .MCM version " + version);
|
||||
m.Comments.Add($"{MOVIEORIGIN} .MCM version {version}");
|
||||
|
||||
// 010 32-byte MD5 of the ROM used
|
||||
byte[] md5 = r.ReadBytes(16);
|
||||
|
@ -1580,7 +1578,7 @@ namespace BizHawk.Client.Common
|
|||
};
|
||||
if (!platforms.ContainsKey(platform))
|
||||
{
|
||||
errorMsg = "Platform " + platform + " not supported.";
|
||||
errorMsg = $"Platform {platform} not supported.";
|
||||
r.Close();
|
||||
fs.Close();
|
||||
return null;
|
||||
|
@ -1601,7 +1599,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
// TODO: Verify if NTSC/"PAL" mode used for the movie can be detected or not.
|
||||
// 100 variable Input data
|
||||
SimpleController controllers = new SimpleController { Definition = new ControllerDefinition { Name = name + " Controller" } };
|
||||
SimpleController controllers = new SimpleController { Definition = new ControllerDefinition { Name = $"{name} Controller" } };
|
||||
int bytes = 256;
|
||||
|
||||
// The input stream consists of 1 byte for power-on and reset, and then X bytes per each input port per frame.
|
||||
|
@ -1632,7 +1630,7 @@ namespace BizHawk.Client.Common
|
|||
ushort controllerState = r.ReadByte();
|
||||
for (int button = 0; button < buttons.Length; button++)
|
||||
{
|
||||
string prefix = platform == "lynx" ? "" : "P" + player + " "; // hack
|
||||
string prefix = platform == "lynx" ? "" : $"P{player} "; // hack
|
||||
controllers[prefix + buttons[button]] = ((controllerState >> button) & 0x1) != 0;
|
||||
}
|
||||
}
|
||||
|
@ -1677,8 +1675,8 @@ namespace BizHawk.Client.Common
|
|||
|
||||
// 0004: 4-byte little endian unsigned int: dega version
|
||||
uint emuVersion = r.ReadUInt32();
|
||||
m.Comments.Add(EMULATIONORIGIN + " Dega version " + emuVersion);
|
||||
m.Comments.Add(MOVIEORIGIN + " .MMV");
|
||||
m.Comments.Add($"{EMULATIONORIGIN} Dega version {emuVersion}");
|
||||
m.Comments.Add($"{MOVIEORIGIN} .MMV");
|
||||
|
||||
// 0008: 4-byte little endian unsigned int: frame count
|
||||
uint frameCount = r.ReadUInt32();
|
||||
|
@ -1771,7 +1769,7 @@ namespace BizHawk.Client.Common
|
|||
byte controllerState = r.ReadByte();
|
||||
for (int button = 0; button < buttons.Length; button++)
|
||||
{
|
||||
controllers["P" + player + " " + buttons[button]] = ((controllerState >> button) & 0x1) != 0;
|
||||
controllers[$"P{player} {buttons[button]}"] = ((controllerState >> button) & 0x1) != 0;
|
||||
}
|
||||
|
||||
if (player == 1)
|
||||
|
@ -1810,8 +1808,8 @@ namespace BizHawk.Client.Common
|
|||
|
||||
// 004 4-byte version string (example "0960")
|
||||
string emuVersion = r.ReadStringFixedAscii(4);
|
||||
m.Comments.Add(EMULATIONORIGIN + " Nintendulator version " + emuVersion);
|
||||
m.Comments.Add(MOVIEORIGIN + " .NMV");
|
||||
m.Comments.Add($"{EMULATIONORIGIN} Nintendulator version {emuVersion}");
|
||||
m.Comments.Add($"{MOVIEORIGIN} .NMV");
|
||||
|
||||
// 008 4-byte file size, not including the 16-byte header
|
||||
r.ReadUInt32();
|
||||
|
@ -1918,7 +1916,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (warningMsg != "")
|
||||
{
|
||||
warningMsg = warningMsg + " is not properly supported.";
|
||||
warningMsg = $"{warningMsg} is not properly supported.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1945,7 +1943,7 @@ namespace BizHawk.Client.Common
|
|||
};
|
||||
if (expansion != 0 && warningMsg == "")
|
||||
{
|
||||
warningMsg = "Expansion port is not properly supported. This movie uses " + expansions[expansion] + ".";
|
||||
warningMsg = $"Expansion port is not properly supported. This movie uses {expansions[expansion]}.";
|
||||
}
|
||||
|
||||
// 003 1-byte number of bytes per frame, plus flags
|
||||
|
@ -1989,7 +1987,7 @@ namespace BizHawk.Client.Common
|
|||
00C (variable) null-terminated UTF-8 text, movie description (currently not implemented)
|
||||
*/
|
||||
string movieDescription = NullTerminated(r.ReadStringFixedAscii((int)r.ReadUInt32()));
|
||||
m.Comments.Add(COMMENT + " " + movieDescription);
|
||||
m.Comments.Add($"{COMMENT} {movieDescription}");
|
||||
|
||||
// ... 4-byte little-endian unsigned int: length of controller data in bytes
|
||||
uint length = r.ReadUInt32();
|
||||
|
@ -2027,7 +2025,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
for (int button = 0; button < buttons.Length; button++)
|
||||
{
|
||||
controllers["P" + player + " " + buttons[button]] = ((controllerState >> button) & 0x1) != 0;
|
||||
controllers[$"P{player} {buttons[button]}"] = ((controllerState >> button) & 0x1) != 0;
|
||||
}
|
||||
}
|
||||
else if (warningMsg == "")
|
||||
|
@ -2084,8 +2082,8 @@ namespace BizHawk.Client.Common
|
|||
return null;
|
||||
}
|
||||
|
||||
m.Comments.Add(EMULATIONORIGIN + " Snes9x version " + version);
|
||||
m.Comments.Add(MOVIEORIGIN + " .SMV");
|
||||
m.Comments.Add($"{EMULATIONORIGIN} Snes9x version {version}");
|
||||
m.Comments.Add($"{MOVIEORIGIN} .SMV");
|
||||
/*
|
||||
008 4-byte little-endian integer: movie "uid" - identifies the movie-savestate relationship, also used as the
|
||||
recording time in Unix epoch format
|
||||
|
@ -2302,7 +2300,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (peripheral != "" && warningMsg == "")
|
||||
{
|
||||
warningMsg = "Unable to import " + peripheral + ".";
|
||||
warningMsg = $"Unable to import {peripheral}.";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2311,13 +2309,13 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
for (int button = 0; button < buttons.Length; button++)
|
||||
{
|
||||
controllers["P" + player + " " + buttons[button]] =
|
||||
controllers[$"P{player} {buttons[button]}"] =
|
||||
((controllerState >> button) & 0x1) != 0;
|
||||
}
|
||||
}
|
||||
else if (warningMsg == "")
|
||||
{
|
||||
warningMsg = "Controller " + player + " not supported.";
|
||||
warningMsg = $"Controller {player} not supported.";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2475,7 +2473,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (isSGB)
|
||||
{
|
||||
m.Comments.Add(SUPERGAMEBOYMODE + " True");
|
||||
m.Comments.Add($"{SUPERGAMEBOYMODE} True");
|
||||
}
|
||||
|
||||
m.Header[HeaderKeys.PLATFORM] = platform;
|
||||
|
@ -2521,8 +2519,8 @@ namespace BizHawk.Client.Common
|
|||
|
||||
// 030 1-byte unsigned char: minor version/revision number of current VBM version, the latest is "1"
|
||||
byte minorVersion = r.ReadByte();
|
||||
m.Comments.Add(MOVIEORIGIN + " .VBM version " + majorVersion + "." + minorVersion);
|
||||
m.Comments.Add(EMULATIONORIGIN + " Visual Boy Advance");
|
||||
m.Comments.Add($"{MOVIEORIGIN} .VBM version {majorVersion}.{minorVersion}");
|
||||
m.Comments.Add($"{EMULATIONORIGIN} Visual Boy Advance");
|
||||
|
||||
// 031 1-byte unsigned char: the internal CRC of the ROM used while recording
|
||||
r.ReadByte();
|
||||
|
@ -2559,7 +2557,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
// The following 128 bytes are for a description of the movie. Both parts must be null-terminated.
|
||||
string movieDescription = NullTerminated(r.ReadStringFixedAscii(128));
|
||||
m.Comments.Add(COMMENT + " " + movieDescription);
|
||||
m.Comments.Add($"{COMMENT} {movieDescription}");
|
||||
r.BaseStream.Position = firstFrameOffset;
|
||||
SimpleController controllers = new SimpleController { Definition = new ControllerDefinition() };
|
||||
controllers.Definition.Name = platform != "GBA"
|
||||
|
@ -2615,7 +2613,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
if (((controllerState >> (button + 10)) & 0x1) != 0)
|
||||
{
|
||||
warningMsg = "Unable to import " + other[button] + " at frame " + frame + ".";
|
||||
warningMsg = $"Unable to import {other[button]} at frame {frame}.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -2660,12 +2658,12 @@ namespace BizHawk.Client.Common
|
|||
|
||||
// 00C 2-byte little-endian integer: movie version 0x0400
|
||||
ushort version = r.ReadUInt16();
|
||||
m.Comments.Add(MOVIEORIGIN + " .VMV version " + version);
|
||||
m.Comments.Add(EMULATIONORIGIN + " VirtuaNES");
|
||||
m.Comments.Add($"{MOVIEORIGIN} .VMV version {version}");
|
||||
m.Comments.Add($"{EMULATIONORIGIN} VirtuaNES");
|
||||
|
||||
// 00E 2-byte little-endian integer: record version
|
||||
ushort recordVersion = r.ReadUInt16();
|
||||
m.Comments.Add(COMMENT + " Record version " + recordVersion);
|
||||
m.Comments.Add($"{COMMENT} Record version {recordVersion}");
|
||||
|
||||
// 010 4-byte flags (control byte)
|
||||
uint flags = r.ReadUInt32();
|
||||
|
@ -2837,12 +2835,12 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
commandName = "NESCMD_EXCONTROLLER, " + (command & 0xFF00);
|
||||
commandName = $"NESCMD_EXCONTROLLER, {(command & 0xFF00)}";
|
||||
}
|
||||
|
||||
if (commandName != "" && warningMsg == "")
|
||||
{
|
||||
warningMsg = "Unable to run command \"" + commandName + "\".";
|
||||
warningMsg = $"Unable to run command \"{commandName}\".";
|
||||
}
|
||||
}
|
||||
else if (controllerState == 0xF3)
|
||||
|
@ -2852,7 +2850,7 @@ namespace BizHawk.Client.Common
|
|||
// TODO: Make a clearer warning message.
|
||||
if (warningMsg == "")
|
||||
{
|
||||
warningMsg = "Unable to run SetSyncExData(" + dwdata + ").";
|
||||
warningMsg = $"Unable to run SetSyncExData({dwdata}).";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2861,7 +2859,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
for (int button = 0; button < buttons.Length; button++)
|
||||
{
|
||||
controllers["P" + player + " " + buttons[button]] = ((controllerState >> button) & 0x1) != 0;
|
||||
controllers[$"P{player} {buttons[button]}"] = ((controllerState >> button) & 0x1) != 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2901,8 +2899,8 @@ namespace BizHawk.Client.Common
|
|||
|
||||
// 003 2-byte little-endian unsigned int: zsnes version number
|
||||
short version = r.ReadInt16();
|
||||
m.Comments.Add(EMULATIONORIGIN + " ZSNES version " + version);
|
||||
m.Comments.Add(MOVIEORIGIN + " .ZMV");
|
||||
m.Comments.Add($"{EMULATIONORIGIN} ZSNES version {version}");
|
||||
m.Comments.Add($"{MOVIEORIGIN} .ZMV");
|
||||
|
||||
// 005 4-byte little-endian integer: CRC32 of the ROM
|
||||
int crc32 = r.ReadInt32();
|
||||
|
@ -2973,7 +2971,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (peripheral != "")
|
||||
{
|
||||
warningMsg = "Unable to import " + peripheral + ".";
|
||||
warningMsg = $"Unable to import {peripheral}.";
|
||||
}
|
||||
|
||||
// 027 1-byte flags:
|
||||
|
@ -3182,14 +3180,14 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
for (int button = 0; button < buttons.Length; button++)
|
||||
{
|
||||
controllers["P" + player + " " + buttons[button]] =
|
||||
controllers[$"P{player} {buttons[button]}"] =
|
||||
((controllerState >> button) & 0x1) != 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (warningMsg == "")
|
||||
{
|
||||
warningMsg = "Controller " + player + " not supported.";
|
||||
warningMsg = $"Controller {player} not supported.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace BizHawk.Client.Common
|
|||
string magic = new string(br.ReadChars(4));
|
||||
if (magic != expectedMagic)
|
||||
{
|
||||
Result.Errors.Add("Not a " + expectedMagic + "file: invalid magic number in file header.");
|
||||
Result.Errors.Add($"Not a {expectedMagic}file: invalid magic number in file header.");
|
||||
return info;
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
for (int button = 3; button < buttons.Length; button++)
|
||||
{
|
||||
controllers["P1 " + buttons[button]] = ((controllerState >> button) & 0x1) != 0;
|
||||
controllers[$"P1 {buttons[button]}"] = ((controllerState >> button) & 0x1) != 0;
|
||||
if (((controllerState >> button) & 0x1) != 0 && button > 15)
|
||||
{
|
||||
continue;
|
||||
|
@ -246,7 +246,7 @@ namespace BizHawk.Client.Common
|
|||
ushort controllerState = br.ReadUInt16();
|
||||
for (int button = 0; button < buttons.Length; button++)
|
||||
{
|
||||
controllers["P2 " + buttons[button]] = ((controllerState >> button) & 0x1) != 0;
|
||||
controllers[$"P2 {buttons[button]}"] = ((controllerState >> button) & 0x1) != 0;
|
||||
if (((controllerState >> button) & 0x1) != 0 && button > 15)
|
||||
{
|
||||
continue;
|
||||
|
@ -291,7 +291,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if ((controlState & 0xFC) != 0)
|
||||
{
|
||||
Result.Warnings.Add("Ignored toggle hack flag on frame " + frame);
|
||||
Result.Warnings.Add($"Ignored toggle hack flag on frame {frame}");
|
||||
}
|
||||
|
||||
movie.AppendFrame(controllers);
|
||||
|
@ -336,7 +336,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
for (int button = 3; button < buttons.Length; button++)
|
||||
{
|
||||
controllers["P1 " + buttons[button]] = br.ReadChar() != '.';
|
||||
controllers[$"P1 {buttons[button]}"] = br.ReadChar() != '.';
|
||||
}
|
||||
|
||||
if (info.Player1Type == OctoshockDll.ePeripheralType.DualShock)
|
||||
|
@ -373,7 +373,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
for (int button = 3; button < buttons.Length; button++)
|
||||
{
|
||||
controllers["P2 " + buttons[button]] = br.ReadChar() != '.';
|
||||
controllers[$"P2 {buttons[button]}"] = br.ReadChar() != '.';
|
||||
}
|
||||
|
||||
if (info.Player2Type == OctoshockDll.ePeripheralType.DualShock)
|
||||
|
@ -423,7 +423,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if ((controlState & 0xFC) != 0)
|
||||
{
|
||||
Result.Warnings.Add("Ignored toggle hack flag on frame " + frame);
|
||||
Result.Warnings.Add($"Ignored toggle hack flag on frame {frame}");
|
||||
}
|
||||
|
||||
// Each controller is terminated with a pipeline.
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (frame > _lagLog.Count)
|
||||
{
|
||||
System.Diagnostics.Debug.Print("Lag Log error. f" + frame + ", log: " + _lagLog.Count);
|
||||
System.Diagnostics.Debug.Print($"Lag Log error. f{frame}, log: {_lagLog.Count}");
|
||||
return; // Can this break anything?
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
if (frame != 0)
|
||||
{
|
||||
ChangeLog.AddGeneralUndo(frame - 1, frame - 1, "Record Frame: " + frame);
|
||||
ChangeLog.AddGeneralUndo(frame - 1, frame - 1, $"Record Frame: {frame}");
|
||||
}
|
||||
|
||||
base.RecordFrame(frame, source);
|
||||
|
@ -35,7 +35,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public override void Truncate(int frame)
|
||||
{
|
||||
bool endBatch = ChangeLog.BeginNewBatch("Truncate Movie: " + frame, true);
|
||||
bool endBatch = ChangeLog.BeginNewBatch($"Truncate Movie: {frame}", true);
|
||||
ChangeLog.AddGeneralUndo(frame, InputLogLength - 1);
|
||||
|
||||
if (frame < Log.Count - 1)
|
||||
|
@ -58,7 +58,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public override void PokeFrame(int frame, IController source)
|
||||
{
|
||||
ChangeLog.AddGeneralUndo(frame, frame, "Set Frame At: " + frame);
|
||||
ChangeLog.AddGeneralUndo(frame, frame, $"Set Frame At: {frame}");
|
||||
|
||||
base.PokeFrame(frame, source);
|
||||
InvalidateAfter(frame);
|
||||
|
@ -68,7 +68,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public void SetFrame(int frame, string source)
|
||||
{
|
||||
ChangeLog.AddGeneralUndo(frame, frame, "Set Frame At: " + frame);
|
||||
ChangeLog.AddGeneralUndo(frame, frame, $"Set Frame At: {frame}");
|
||||
|
||||
SetFrameAt(frame, source);
|
||||
InvalidateAfter(frame);
|
||||
|
@ -78,7 +78,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public override void ClearFrame(int frame)
|
||||
{
|
||||
ChangeLog.AddGeneralUndo(frame, frame, "Clear Frame: " + frame);
|
||||
ChangeLog.AddGeneralUndo(frame, frame, $"Clear Frame: {frame}");
|
||||
|
||||
base.ClearFrame(frame);
|
||||
InvalidateAfter(frame);
|
||||
|
@ -88,7 +88,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public void RemoveFrame(int frame)
|
||||
{
|
||||
bool endBatch = ChangeLog.BeginNewBatch("Remove Frame: " + frame, true);
|
||||
bool endBatch = ChangeLog.BeginNewBatch($"Remove Frame: {frame}", true);
|
||||
ChangeLog.AddGeneralUndo(frame, InputLogLength - 1);
|
||||
|
||||
Log.RemoveAt(frame);
|
||||
|
@ -181,7 +181,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public void RemoveFrames(int removeStart, int removeUpTo, bool fromHistory = false)
|
||||
{
|
||||
bool endBatch = ChangeLog.BeginNewBatch("Remove Frames: " + removeStart + "-" + removeUpTo, true);
|
||||
bool endBatch = ChangeLog.BeginNewBatch($"Remove Frames: {removeStart}-{removeUpTo}", true);
|
||||
ChangeLog.AddGeneralUndo(removeStart, InputLogLength - 1);
|
||||
|
||||
for (int i = removeUpTo - 1; i >= removeStart; i--)
|
||||
|
@ -225,7 +225,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public void InsertInput(int frame, string inputState)
|
||||
{
|
||||
bool endBatch = ChangeLog.BeginNewBatch("Insert Frame: " + frame, true);
|
||||
bool endBatch = ChangeLog.BeginNewBatch($"Insert Frame: {frame}", true);
|
||||
ChangeLog.AddGeneralUndo(frame, InputLogLength);
|
||||
|
||||
Log.Insert(frame, inputState);
|
||||
|
@ -258,7 +258,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public void InsertInput(int frame, IEnumerable<string> inputLog)
|
||||
{
|
||||
bool endBatch = ChangeLog.BeginNewBatch("Insert Frame: " + frame, true);
|
||||
bool endBatch = ChangeLog.BeginNewBatch($"Insert Frame: {frame}", true);
|
||||
ChangeLog.AddGeneralUndo(frame, InputLogLength + inputLog.Count() - 1);
|
||||
|
||||
Log.InsertRange(frame, inputLog);
|
||||
|
@ -307,7 +307,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public void CopyOverInput(int frame, IEnumerable<IController> inputStates)
|
||||
{
|
||||
ChangeLog.BeginNewBatch("Copy Over Input: " + frame);
|
||||
ChangeLog.BeginNewBatch($"Copy Over Input: {frame}");
|
||||
var lg = LogGeneratorInstance();
|
||||
var states = inputStates.ToList();
|
||||
|
||||
|
@ -316,7 +316,7 @@ namespace BizHawk.Client.Common
|
|||
ExtendMovieForEdit(states.Count + frame - Log.Count);
|
||||
}
|
||||
|
||||
ChangeLog.AddGeneralUndo(frame, frame + inputStates.Count() - 1, "Copy Over Input: " + frame);
|
||||
ChangeLog.AddGeneralUndo(frame, frame + inputStates.Count() - 1, $"Copy Over Input: {frame}");
|
||||
|
||||
for (int i = 0; i < states.Count; i++)
|
||||
{
|
||||
|
@ -338,7 +338,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
public void InsertEmptyFrame(int frame, int count = 1, bool fromHistory = false)
|
||||
{
|
||||
bool endBatch = ChangeLog.BeginNewBatch("Insert Empty Frame: " + frame, true);
|
||||
bool endBatch = ChangeLog.BeginNewBatch($"Insert Empty Frame: {frame}", true);
|
||||
ChangeLog.AddGeneralUndo(frame, InputLogLength + count - 1);
|
||||
|
||||
var lg = LogGeneratorInstance();
|
||||
|
@ -422,7 +422,7 @@ namespace BizHawk.Client.Common
|
|||
Changes = true;
|
||||
InvalidateAfter(frame);
|
||||
|
||||
ChangeLog.AddBoolToggle(frame, buttonName, !adapter.IsPressed(buttonName), "Toggle " + buttonName + ": " + frame);
|
||||
ChangeLog.AddBoolToggle(frame, buttonName, !adapter.IsPressed(buttonName), $"Toggle {buttonName}: {frame}");
|
||||
}
|
||||
|
||||
public void SetBoolState(int frame, string buttonName, bool val)
|
||||
|
@ -444,7 +444,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
InvalidateAfter(frame);
|
||||
Changes = true;
|
||||
ChangeLog.AddBoolToggle(frame, buttonName, old, "Set " + buttonName + "(" + (val ? "On" : "Off") + "): " + frame);
|
||||
ChangeLog.AddBoolToggle(frame, buttonName, old, $"Set {buttonName}({(val ? "On" : "Off")}): {frame}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -455,7 +455,7 @@ namespace BizHawk.Client.Common
|
|||
ExtendMovieForEdit(frame + count - Log.Count);
|
||||
}
|
||||
|
||||
ChangeLog.AddGeneralUndo(frame, frame + count - 1, "Set " + buttonName + "(" + (val ? "On" : "Off") + "): " + frame + "-" + (frame + count - 1));
|
||||
ChangeLog.AddGeneralUndo(frame, frame + count - 1, $"Set {buttonName}({(val ? "On" : "Off")}): {frame}-{(frame + count - 1)}");
|
||||
|
||||
int changed = -1;
|
||||
for (int i = 0; i < count; i++)
|
||||
|
@ -502,7 +502,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
InvalidateAfter(frame);
|
||||
Changes = true;
|
||||
ChangeLog.AddFloatChange(frame, buttonName, old, val, "Set " + buttonName + "(" + val + "): " + frame);
|
||||
ChangeLog.AddFloatChange(frame, buttonName, old, val, $"Set {buttonName}({val}): {frame}");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -513,7 +513,7 @@ namespace BizHawk.Client.Common
|
|||
ExtendMovieForEdit(frame - Log.Count + 1);
|
||||
}
|
||||
|
||||
ChangeLog.AddGeneralUndo(frame, frame + count - 1, "Set " + buttonName + "(" + val + "): " + frame + "-" + (frame + count - 1));
|
||||
ChangeLog.AddGeneralUndo(frame, frame + count - 1, $"Set {buttonName}({val}): {frame}-{(frame + count - 1)}");
|
||||
|
||||
int changed = -1;
|
||||
for (int i = 0; i < count; i++)
|
||||
|
|
|
@ -273,7 +273,7 @@ namespace BizHawk.Client.Common
|
|||
|
||||
if (name == "")
|
||||
{
|
||||
name = "Undo step " + _totalSteps;
|
||||
name = $"Undo step {_totalSteps}";
|
||||
}
|
||||
|
||||
bool ret = false;
|
||||
|
@ -349,11 +349,11 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
if (oldPosition == -1)
|
||||
{
|
||||
name = "Set Marker at frame " + newMarker.Frame;
|
||||
name = $"Set Marker at frame {newMarker.Frame}";
|
||||
}
|
||||
else
|
||||
{
|
||||
name = "Remove Marker at frame " + oldPosition;
|
||||
name = $"Remove Marker at frame {oldPosition}";
|
||||
}
|
||||
|
||||
AddMovieAction(name);
|
||||
|
|
|
@ -55,7 +55,7 @@ namespace BizHawk.Client.Common
|
|||
_progressReportWorker = progressReportWorker;
|
||||
if (!Global.Emulator.HasSavestates())
|
||||
{
|
||||
throw new InvalidOperationException("Cannot create a TasMovie against a core that does not implement IStatable");
|
||||
throw new InvalidOperationException($"Cannot create a {nameof(TasMovie)} against a core that does not implement {nameof(IStatable)}");
|
||||
}
|
||||
|
||||
ChangeLog = new TasMovieChangeLog(this);
|
||||
|
@ -65,7 +65,7 @@ namespace BizHawk.Client.Common
|
|||
Markers = new TasMovieMarkerList(this);
|
||||
Markers.CollectionChanged += Markers_CollectionChanged;
|
||||
Markers.Add(0, startsFromSavestate ? "Savestate" : "Power on");
|
||||
BindMarkersToInput = true;
|
||||
BindMarkersToInput = false;
|
||||
CurrentBranch = -1;
|
||||
}
|
||||
|
||||
|
@ -74,7 +74,7 @@ namespace BizHawk.Client.Common
|
|||
_progressReportWorker = progressReportWorker;
|
||||
if (!Global.Emulator.HasSavestates())
|
||||
{
|
||||
throw new InvalidOperationException("Cannot create a TasMovie against a core that does not implement IStatable");
|
||||
throw new InvalidOperationException($"Cannot create a {nameof(TasMovie)} against a core that does not implement {nameof(IStatable)}");
|
||||
}
|
||||
|
||||
ChangeLog = new TasMovieChangeLog(this);
|
||||
|
@ -84,7 +84,7 @@ namespace BizHawk.Client.Common
|
|||
Markers = new TasMovieMarkerList(this);
|
||||
Markers.CollectionChanged += Markers_CollectionChanged;
|
||||
Markers.Add(0, startsFromSavestate ? "Savestate" : "Power on");
|
||||
BindMarkersToInput = true;
|
||||
BindMarkersToInput = false;
|
||||
CurrentBranch = -1;
|
||||
}
|
||||
|
||||
|
@ -509,17 +509,13 @@ namespace BizHawk.Client.Common
|
|||
Log?.Dispose();
|
||||
Log = branch.InputLog.Clone();
|
||||
|
||||
_lagLog.FromLagLog(branch.LagLog);
|
||||
|
||||
// if there are branch states, they will be loaded anyway
|
||||
// but if there's none, or only *after* divergent point, don't invalidate the entire movie anymore
|
||||
if (divergentPoint.HasValue)
|
||||
{
|
||||
_stateManager.Invalidate(divergentPoint.Value);
|
||||
InvalidateAfter(divergentPoint.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
_stateManager.Invalidate(branch.InputLog.Count);
|
||||
InvalidateAfter(branch.InputLog.Count);
|
||||
}
|
||||
|
||||
if (BindMarkersToInput) // pretty critical not to erase them
|
||||
|
|
|
@ -384,7 +384,17 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
if (_states.Any())
|
||||
{
|
||||
StateManagerState power = _states.Values.First(s => s.Frame == 0);
|
||||
var temp_state = _states.Values;
|
||||
StateManagerState power = null;
|
||||
if (temp_state[0].Frame==0)
|
||||
{
|
||||
power = _states.Values.First(s => s.Frame == 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
power = _states.Values[0];
|
||||
}
|
||||
|
||||
_states.Clear();
|
||||
SetState(0, power.State);
|
||||
Used = (ulong)power.State.Length;
|
||||
|
|
|
@ -192,7 +192,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
if (_mHead == null)
|
||||
{
|
||||
throw new InvalidOperationException("Attempted to pop from an empty data structure");
|
||||
throw new InvalidOperationException($"Attempted to {nameof(Pop)} from an empty data structure");
|
||||
}
|
||||
|
||||
var ret = _mHead.Value;
|
||||
|
@ -213,7 +213,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
if (_mHead == null)
|
||||
{
|
||||
throw new InvalidOperationException("Attempted to peek from an empty data structure");
|
||||
throw new InvalidOperationException($"Attempted to {nameof(Peek)} from an empty data structure");
|
||||
}
|
||||
|
||||
return _mHead.Value;
|
||||
|
@ -223,7 +223,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
if (_mTail == null)
|
||||
{
|
||||
throw new InvalidOperationException("Attempted to dequeue from an empty data structure");
|
||||
throw new InvalidOperationException($"Attempted to {nameof(Dequeue)} from an empty data structure");
|
||||
}
|
||||
|
||||
var ret = _mTail.Value;
|
||||
|
|
|
@ -200,24 +200,7 @@ namespace BizHawk.Client.Common
|
|||
/// Get a string representation of difference
|
||||
/// between current value and the previous one
|
||||
/// </summary>
|
||||
public override string Diff
|
||||
{
|
||||
get
|
||||
{
|
||||
string diff = "";
|
||||
int diffVal = _value - _previous;
|
||||
if (diffVal > 0)
|
||||
{
|
||||
diff = "+";
|
||||
}
|
||||
else if (diffVal < 0)
|
||||
{
|
||||
diff = "-";
|
||||
}
|
||||
|
||||
return $"{diff}{((byte)Math.Abs(diffVal))}";
|
||||
}
|
||||
}
|
||||
public override string Diff => $"{_value - (short)_previous:+#;-#;0}";
|
||||
|
||||
/// <summary>
|
||||
/// Get the maximum possible value
|
||||
|
|
|
@ -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);
|
||||
|
@ -231,7 +231,7 @@ namespace BizHawk.Client.Common
|
|||
/// Get a string representation of difference
|
||||
/// between current value and the previous one
|
||||
/// </summary>
|
||||
public override string Diff => (_previous - _value).ToString();
|
||||
public override string Diff => $"{_value - (long)_previous:+#;-#;0}";
|
||||
|
||||
/// <summary>
|
||||
/// Get the maximum possible value
|
||||
|
|
|
@ -46,7 +46,7 @@ namespace BizHawk.Client.Common
|
|||
}
|
||||
else
|
||||
{
|
||||
throw new ArgumentException($"DisplayType {type} is invalid for this type of Watch", nameof(type));
|
||||
throw new ArgumentException($"{nameof(DisplayType)} {type} is invalid for this type of {nameof(Watch)}", nameof(type));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -573,7 +573,7 @@ namespace BizHawk.Client.Common
|
|||
{
|
||||
if (_domain != null)
|
||||
{
|
||||
return "X" + (_domain.Size - 1).NumHexDigits();
|
||||
return $"X{(_domain.Size - 1).NumHexDigits()}";
|
||||
}
|
||||
|
||||
return "";
|
||||
|
|
|
@ -214,24 +214,7 @@ namespace BizHawk.Client.Common
|
|||
/// Get a string representation of difference
|
||||
/// between current value and the previous one
|
||||
/// </summary>
|
||||
public override string Diff
|
||||
{
|
||||
get
|
||||
{
|
||||
string diff = "";
|
||||
int diffVal = _value - _previous;
|
||||
if (diffVal > 0)
|
||||
{
|
||||
diff = "+";
|
||||
}
|
||||
else if (diffVal < 0)
|
||||
{
|
||||
diff = "-";
|
||||
}
|
||||
|
||||
return $"{diff}{((ushort)Math.Abs(diffVal))}";
|
||||
}
|
||||
}
|
||||
public override string Diff => $"{_value - (int)_previous:+#;-#;0}";
|
||||
|
||||
/// <summary>
|
||||
/// Get the maximum possible value
|
||||
|
|
|
@ -14,7 +14,7 @@ namespace BizHawk.Client.DiscoHawk
|
|||
public About()
|
||||
{
|
||||
InitializeComponent();
|
||||
lblVersion.Text = "v" + System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
|
||||
lblVersion.Text = $"v{System.Reflection.Assembly.GetExecutingAssembly().GetName().Version}";
|
||||
}
|
||||
|
||||
private void richTextBox1_LinkClicked(object sender, LinkClickedEventArgs e)
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace BizHawk.Client.DiscoHawk
|
|||
for (int sector = 0; sector < trackLength; sector++)
|
||||
dsr.ReadLBA_2352(startLba + sector, waveData, sector * 2352);
|
||||
|
||||
string mp3Path = string.Format("{0} - Track {1:D2}.mp3", Path.Combine(path, filebase), track.Number);
|
||||
string mp3Path = $"{Path.Combine(path, filebase)} - Track {track.Number:D2}.mp3";
|
||||
if (File.Exists(mp3Path))
|
||||
{
|
||||
if (!confirmed)
|
||||
|
|
|
@ -102,7 +102,7 @@ namespace BizHawk.Client.DiscoHawk
|
|||
return asm;
|
||||
|
||||
//load missing assemblies by trying to find them in the dll directory
|
||||
string dllname = new AssemblyName(args.Name).Name + ".dll";
|
||||
string dllname = $"{new AssemblyName(args.Name).Name}.dll";
|
||||
string directory = Path.Combine(GetExeDirectoryAbsolute(), "dll");
|
||||
string fname = Path.Combine(directory, dllname);
|
||||
if (!File.Exists(fname)) return null;
|
||||
|
@ -120,7 +120,7 @@ namespace BizHawk.Client.DiscoHawk
|
|||
static extern bool DeleteFileW([MarshalAs(UnmanagedType.LPWStr)]string lpFileName);
|
||||
static void RemoveMOTW(string path)
|
||||
{
|
||||
DeleteFileW(path + ":Zone.Identifier");
|
||||
DeleteFileW($"{path}:Zone.Identifier");
|
||||
}
|
||||
|
||||
static void WhackAllMOTW(string dllDir)
|
||||
|
@ -416,8 +416,8 @@ namespace BizHawk.Client.DiscoHawk
|
|||
sw.Write(" ");
|
||||
sw.Write(new string('-', count * 4));
|
||||
sw.WriteLine();
|
||||
sw_dump_chunk_one(string.Format("SRC #{0,6} ({1})", lba, new Timestamp(lba)), lba, src_databuf, addr, count);
|
||||
sw_dump_chunk_one(string.Format("DST #{0,6} ({1})", lba, new Timestamp(lba)), lba, dst_databuf, addr, count);
|
||||
sw_dump_chunk_one($"SRC #{lba,6} ({new Timestamp(lba)})", lba, src_databuf, addr, count);
|
||||
sw_dump_chunk_one($"DST #{lba,6} ({new Timestamp(lba)})", lba, dst_databuf, addr, count);
|
||||
};
|
||||
|
||||
//verify each sector contents
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue