Merge branch 'master' into appleii_fixattempt

This commit is contained in:
James Groom 2019-03-28 20:25:11 +11:00 committed by GitHub
commit 59ad94f9b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
782 changed files with 17705 additions and 8496 deletions

1
.gitignore vendored
View File

@ -73,3 +73,4 @@ ExternalCoreProjects/Virtu/bin/*.*
libsnes/vs2015/libsnes.VC.db
waterbox/**/*.wbx
waterbox/**/*.wbx.in
/BizHawkTool_template.zip

18
Assets/EmuHawkMono.sh Executable file
View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

BIN
Assets/libblip_buf.so Executable file

Binary file not shown.

View File

@ -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>

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}

View File

@ -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*/
}
}
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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);
}
}
}
}

View File

@ -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();
}
}
}

View File

@ -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();
}
}
}

View File

@ -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;
}
}
}

View File

@ -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;
}
}
}
}

View File

@ -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);
}
}
}

View File

@ -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
{
}
}

View File

@ -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);
}
}
}
}

View File

@ -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");
}
}

View File

@ -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));
}
}
}

View File

@ -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);

View File

@ -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;

View File

@ -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");
}
}

View File

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
namespace BizHawk.Client.ApiHawk
{
public interface IApiContainer
{
Dictionary<Type, IExternalApi> Libraries { get; set; }
}
}

View File

@ -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
}
}

View File

@ -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);
}
}

View File

@ -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
{
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,10 @@
using System.Collections.Generic;
namespace BizHawk.Client.ApiHawk
{
public interface IInput : IExternalApi
{
Dictionary<string, bool> Get();
Dictionary<string, dynamic> GetMouse();
}
}

View File

@ -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);
}
}

View File

@ -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
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,10 @@
namespace BizHawk.Client.ApiHawk
{
public interface IMemorySaveState : IExternalApi
{
string SaveCoreStateToMemory();
void LoadCoreStateFromMemory(string identifier);
void DeleteState(string identifier);
void ClearInMemoryStates();
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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 = "");
}
}

View File

@ -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();
}
}

View File

@ -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);
}
}

View File

@ -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; }
}
}

View File

@ -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);
}
}

View File

@ -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)
{

View File

@ -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(

View File

@ -31,6 +31,7 @@
VirtualBoy,
NeoGeoPocket,
ZXSpectrum,
AmstradCPC
AmstradCPC,
GGL
}
}

View File

@ -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;

View File

@ -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" />

View File

@ -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);
}

View File

@ -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;
}
}

View File

@ -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()
{}

View File

@ -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"] ??

View File

@ -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;

View File

@ -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();

View File

@ -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);
}

View File

@ -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}\"");
}
}

View File

@ -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;

View File

@ -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[]
{

View File

@ -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");
}
}

View File

@ -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))

View File

@ -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)}");
}
}

View File

@ -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}");
}
}
}

View File

@ -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)

View File

@ -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);
}
}
}

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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;

View File

@ -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();

View File

@ -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));

View File

@ -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

View File

@ -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

View File

@ -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}");
}
};
}

View File

@ -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}");
}
}

View File

@ -35,7 +35,7 @@ namespace BizHawk.Client.Common
return "Recording None";
}
return "Recording Player " + CurrentPlayer;
return $"Recording Player {CurrentPlayer}";
}
}

View File

@ -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(" --> ");

View File

@ -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--;
}

View File

@ -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)
{

View File

@ -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;
}

View File

@ -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++]);
}
}

View File

@ -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("|");

View File

@ -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)

View File

@ -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;
}

View File

@ -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;

View File

@ -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;

View File

@ -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();

View File

@ -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.";
}
}
}

View File

@ -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.

View File

@ -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?
}

View File

@ -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++)

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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 "";

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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