Completely refactored PluginAPI to extend ApiHawk. Ecco2AssistantPlugin is now an external tool.

This commit is contained in:
upthorn 2018-12-22 10:40:30 -08:00
parent d3cb19e56b
commit aba1da071d
57 changed files with 2859 additions and 2204 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

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

@ -2,6 +2,7 @@
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;
@ -12,11 +13,32 @@ using BizHawk.Emulation.Cores.Sega.MasterSystem;
using BizHawk.Emulation.Cores.WonderSwan;
using BizHawk.Emulation.Cores.Consoles.Nintendo.QuickNES;
namespace BizHawk.Client.Common
namespace BizHawk.Client.ApiHawk
{
[Description("A library for interacting with the currently loaded emulator core")]
public sealed class EmulatorPluginLibrary : PluginLibraryBase
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; }
@ -41,12 +63,12 @@ namespace BizHawk.Client.Common
public Action FrameAdvanceCallback { get; set; }
public Action YieldCallback { get; set; }
public EmulatorPluginLibrary() : base()
public EmuApi()
{ }
public static void DisplayVsync(bool enabled)
public void DisplayVsync(bool enabled)
{
Global.Config.VSync = enabled;
EmuStatic.DisplayVsync(enabled);
}
public void FrameAdvance()
@ -166,9 +188,9 @@ namespace BizHawk.Client.Common
}
}
public static string GetSystemId()
public string GetSystemId()
{
return Global.Game.System;
return EmuStatic.GetSystemId();
}
public bool IsLagged()
@ -217,14 +239,39 @@ namespace BizHawk.Client.Common
}
}
public static void LimitFramerate(bool enabled)
public void LimitFramerate(bool enabled)
{
Global.Config.ClockThrottle = enabled;
EmuStatic.LimitFramerate(enabled);
}
public static void MinimizeFrameskip(bool enabled)
public void MinimizeFrameskip(bool enabled)
{
Global.Config.AutoMinimizeSkipping = 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()
{
@ -407,30 +454,5 @@ namespace BizHawk.Client.Common
return true;
}
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 "";
}
}
}

View File

@ -1,16 +1,16 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using BizHawk.Client.Common;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
namespace BizHawk.Client.ApiHawk
{
public sealed class GameInfoPluginLibrary : PluginLibraryBase
public sealed class GameInfoApi : IGameInfo
{
[OptionalService]
private IBoardInfo BoardInfo { get; set; }
public GameInfoPluginLibrary() : base()
public GameInfoApi()
{ }
public string GetRomName()

View File

@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
namespace BizHawk.Client.Common
using BizHawk.Client.Common;
namespace BizHawk.Client.ApiHawk
{
public sealed class JoypadPluginLibrary : PluginLibraryBase
public sealed class JoypadApi : IJoypad
{
public JoypadPluginLibrary() : base()
public JoypadApi()
{ }
public Dictionary<string,dynamic> Get(int? controller = null)

View File

@ -5,20 +5,16 @@ using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
using BizHawk.Common.BufferExtensions;
namespace BizHawk.Client.Common
namespace BizHawk.Client.ApiHawk
{
public sealed class MemoryPluginLibrary : PluginMemoryBase
public sealed class MemApi : MemApiBase, IMem
{
private MemoryDomain _currentMemoryDomain;
private bool _isBigEndian = false;
public MemoryPluginLibrary()
public MemApi()
: base()
{
}
public void SetBigEndian()
{
_isBigEndian = true;
}
protected override MemoryDomain Domain
{
@ -44,6 +40,11 @@ namespace BizHawk.Client.Common
#region Unique Library Methods
public void SetBigEndian(bool enabled = true)
{
_isBigEndian = enabled;
}
public List<string> GetMemoryDomainList()
{
var list = new List<string>();
@ -198,16 +199,16 @@ namespace BizHawk.Client.Common
return (sbyte)ReadUnsignedByte(addr, domain);
}
public void WriteS8(long addr, uint value, string domain = null)
{
WriteUnsignedByte(addr, value, 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);

View File

@ -3,12 +3,12 @@ using System.Collections.Generic;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
namespace BizHawk.Client.Common
namespace BizHawk.Client.ApiHawk
{
/// <summary>
/// Base class for the Memory and MainMemory plugin libraries
/// </summary>
public abstract class PluginMemoryBase : PluginLibraryBase
public abstract class MemApiBase : IExternalApi
{
[RequiredService]
protected IEmulator Emulator { get; set; }
@ -18,7 +18,7 @@ namespace BizHawk.Client.Common
protected abstract MemoryDomain Domain { get; }
protected PluginMemoryBase() : base()
protected MemApiBase()
{ }
protected IMemoryDomains DomainList

View File

@ -3,14 +3,14 @@
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
namespace BizHawk.Client.Common
namespace BizHawk.Client.ApiHawk
{
public sealed class MemoryEventsPluginLibrary : PluginLibraryBase
public sealed class MemEventsApi : IMemEvents
{
[RequiredService]
private IDebuggable DebuggableCore { get; set; }
public MemoryEventsPluginLibrary () : base()
public MemEventsApi () : base()
{ }
public void AddReadCallback(Action cb, uint address, string domain)

View File

@ -4,11 +4,11 @@ using System.IO;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
namespace BizHawk.Client.ApiHawk
{
public sealed class MemorySavestatePluginLibrary : PluginLibraryBase
public sealed class MemorySaveStateApi : IMemorySaveState
{
public MemorySavestatePluginLibrary() : base()
public MemorySaveStateApi()
{ }
[RequiredService]

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

@ -1,6 +1,6 @@
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
namespace BizHawk.Client.ApiHawk
{
public abstract class PluginBase : IPlugin
{
@ -13,7 +13,7 @@ namespace BizHawk.Client.Common
/// or register memory callbacks in
/// their Init function.
/// </summary>
protected IPluginAPI _api;
protected IApiContainer _api;
public PluginBase() { }
@ -41,7 +41,7 @@ namespace BizHawk.Client.Common
public virtual void LoadStateCallback(string name) { }
public virtual void InputPollCallback() { }
public virtual void ExitCallback() { }
public virtual void Init (IPluginAPI api)
public virtual void Init (IApiContainer api)
{
_api = api;
Running = true;

View File

@ -3,11 +3,11 @@ using System.Collections.Generic;
using System.ComponentModel;
using System.Data.SQLite;
namespace BizHawk.Client.Common
namespace BizHawk.Client.ApiHawk
{
public sealed class SQLPluginLibrary : PluginLibraryBase
public sealed class SqlApi : ISql
{
public SQLPluginLibrary() : base()
public SqlApi() : base()
{ }
SQLiteConnection m_dbConnection;
@ -125,6 +125,5 @@ namespace BizHawk.Client.Common
return sqlEX.Message;
}
}
}
}

View File

@ -3,11 +3,11 @@ using System.ComponentModel;
using BizHawk.Client.Common;
namespace BizHawk.Client.Common
namespace BizHawk.Client.ApiHawk
{
public sealed class UserDataPluginLibrary : PluginLibraryBase
public sealed class UserDataApi : IUserData
{
public UserDataPluginLibrary() : base()
public UserDataApi() : base()
{ }
public void Set(string name, object value)

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

@ -5,6 +5,7 @@ using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Emulation.Cores.PCEngine;
using BizHawk.Emulation.Cores.Sega.MasterSystem;
@ -21,6 +22,9 @@ namespace BizHawk.Client.ApiHawk
{
#region Fields
private static IEmulator Emulator;
private static IVideoProvider VideoProvider;
private static readonly Assembly clientAssembly;
private static readonly object clientMainFormInstance;
private static readonly Type mainFormClass;
@ -68,24 +72,57 @@ namespace BizHawk.Client.ApiHawk
mainFormClass = clientAssembly.GetType("BizHawk.Client.EmuHawk.MainForm");
}
public static void UpdateEmulatorAndVP(IEmulator emu = null)
{
Emulator = emu;
VideoProvider = Emulation.Common.IEmulatorExtensions.Extensions.AsVideoProviderOrDefault(emu);
}
#endregion
#region Methods
#region Helpers
private static void InvokeMainFormMethod(string name, dynamic[] paramList = null)
{
List<Type> typeList = new List<Type>();
MethodInfo method;
if (paramList != null)
{
foreach (var obj in paramList)
{
typeList.Add(obj.GetType());
}
method = mainFormClass.GetMethod(name, typeList.ToArray());
}
else method = mainFormClass.GetMethod(name);
method.Invoke(clientMainFormInstance, paramList);
}
private static object GetMainFormField(string name)
{
return mainFormClass.GetField(name);
}
private static void SetMainFormField(string name, object value)
{
mainFormClass.GetField(name).SetValue(clientMainFormInstance, value);
}
#endregion
#region Public
/// <summary>
/// THE FrameAdvance stuff
/// </summary>
public static void DoFrameAdvance()
{
MethodInfo method = mainFormClass.GetMethod("FrameAdvance");
method.Invoke(clientMainFormInstance, null);
InvokeMainFormMethod("FrameAdvance", null);
method = mainFormClass.GetMethod("StepRunLoop_Throttle", BindingFlags.NonPublic | BindingFlags.Instance);
method.Invoke(clientMainFormInstance, null);
InvokeMainFormMethod("StepRunLoop_Throttle", null);
method = mainFormClass.GetMethod("Render", BindingFlags.NonPublic | BindingFlags.Instance);
method.Invoke(clientMainFormInstance, null);
InvokeMainFormMethod("Render", null);
}
/// <summary>
@ -124,8 +161,7 @@ namespace BizHawk.Client.ApiHawk
/// <param name="name">Savetate friendly name</param>
public static void LoadState(string name)
{
MethodInfo method = mainFormClass.GetMethod("LoadState");
method.Invoke(clientMainFormInstance, new object[] { Path.Combine(PathManager.GetSaveStatePath(Global.Game), string.Format("{0}.{1}", name, "State")), name, false, false });
InvokeMainFormMethod("LoadState", new object[] { Path.Combine(PathManager.GetSaveStatePath(Global.Game), string.Format("{0}.{1}", name, "State")), name, false, false });
}
@ -194,12 +230,11 @@ namespace BizHawk.Client.ApiHawk
/// <summary>
/// Raise when a rom is successfully Loaded
/// </summary>
public static void OnRomLoaded()
public static void OnRomLoaded(IEmulator emu)
{
if (RomLoaded != null)
{
RomLoaded(null, EventArgs.Empty);
}
Emulator = emu;
VideoProvider = Emulation.Common.IEmulatorExtensions.Extensions.AsVideoProviderOrDefault(emu);
RomLoaded?.Invoke(null, EventArgs.Empty);
allJoypads = new List<Joypad>(RunningSystem.MaxControllers);
for (int i = 1; i <= RunningSystem.MaxControllers; i++)
@ -215,11 +250,9 @@ namespace BizHawk.Client.ApiHawk
/// <param name="name">Savetate friendly name</param>
public static void SaveState(string name)
{
MethodInfo method = mainFormClass.GetMethod("SaveState");
method.Invoke(clientMainFormInstance, new object[] { Path.Combine(PathManager.GetSaveStatePath(Global.Game), string.Format("{0}.{1}", name, "State")), name, false });
InvokeMainFormMethod("SaveState", new object[] { Path.Combine(PathManager.GetSaveStatePath(Global.Game), string.Format("{0}.{1}", name, "State")), name, false });
}
/// <summary>
/// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements
/// </summary>
@ -227,24 +260,23 @@ namespace BizHawk.Client.ApiHawk
/// <param name="top">Top padding</param>
/// <param name="right">Right padding</param>
/// <param name="bottom">Bottom padding</param>
public static void SetExtraPadding(int left, int top, int right, int bottom)
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("ClientExtraPadding");
f = f.FieldType.GetField("GameExtraPadding");
f.SetValue(displayManager, new Padding(left, top, right, bottom));
MethodInfo resize = mainFormClass.GetMethod("FrameBufferResized");
resize.Invoke(clientMainFormInstance, null);
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 SetExtraPadding(int left)
public static void SetGameExtraPadding(int left)
{
SetExtraPadding(left, 0, 0, 0);
SetGameExtraPadding(left, 0, 0, 0);
}
/// <summary>
@ -252,9 +284,9 @@ namespace BizHawk.Client.ApiHawk
/// </summary>
/// <param name="left">Left padding</param>
/// <param name="top">Top padding</param>
public static void SetExtraPadding(int left, int top)
public static void SetGameExtraPadding(int left, int top)
{
SetExtraPadding(left, top, 0, 0);
SetGameExtraPadding(left, top, 0, 0);
}
/// <summary>
@ -263,9 +295,56 @@ namespace BizHawk.Client.ApiHawk
/// <param name="left">Left padding</param>
/// <param name="top">Top padding</param>
/// <param name="right">Right padding</param>
public static void SetExtraPadding(int left, int top, int right)
public static void SetGameExtraPadding(int left, int top, int right)
{
SetExtraPadding(left, top, right, 0);
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
/// </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 SetClientExtraPadding(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("ClientExtraPadding");
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 SetClientExtraPadding(int left)
{
SetClientExtraPadding(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 SetClientExtraPadding(int left, int top)
{
SetClientExtraPadding(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 SetClientExtraPadding(int left, int top, int right)
{
SetClientExtraPadding(left, top, right, 0);
}
@ -327,8 +406,7 @@ namespace BizHawk.Client.ApiHawk
/// </summary>
public static void UnpauseEmulation()
{
MethodInfo method = mainFormClass.GetMethod("UnpauseEmulator");
method.Invoke(clientMainFormInstance, null);
InvokeMainFormMethod("UnpauseEmulator", null);
}
#endregion Public
@ -375,6 +453,275 @@ namespace BizHawk.Client.ApiHawk
}
}
public static void CloseEmulator()
{
InvokeMainFormMethod("CloseEmulator");
}
public static void CloseEmulatorWithCode(int exitCode)
{
InvokeMainFormMethod("CloseEmulator", new object[] {exitCode});
}
public static int BorderHeight()
{
var point = new System.Drawing.Point(0, 0);
Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin");
FieldInfo f = t.GetField("DisplayManager");
object displayManager = f.GetValue(null);
MethodInfo m = t.GetMethod("TransFormPoint");
point = (System.Drawing.Point) m.Invoke(displayManager, new object[] { point });
return point.Y;
}
public static int BorderWidth()
{
var point = new System.Drawing.Point(0, 0);
Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin");
FieldInfo f = t.GetField("DisplayManager");
object displayManager = f.GetValue(null);
MethodInfo m = t.GetMethod("TransFormPoint");
point = (System.Drawing.Point)m.Invoke(displayManager, new object[] { point });
return point.X;
}
public static int BufferHeight()
{
return VideoProvider.BufferHeight;
}
public static int BufferWidth()
{
return VideoProvider.BufferWidth;
}
public static void ClearAutohold()
{
InvokeMainFormMethod("ClearHolds");
}
public static void CloseRom()
{
InvokeMainFormMethod("CloseRom");
}
public static void DisplayMessages(bool value)
{
Global.Config.DisplayMessages = value;
}
public static void EnableRewind(bool enabled)
{
InvokeMainFormMethod("EnableRewind", new object[] {enabled});
}
public static void FrameSkip(int numFrames)
{
if (numFrames > 0)
{
Global.Config.FrameSkip = numFrames;
InvokeMainFormMethod("FrameSkipMessage");
}
else
{
Console.WriteLine("Invalid frame skip value");
}
}
public static int GetTargetScanlineIntensity()
{
return Global.Config.TargetScanlineFilterIntensity;
}
public static int GetWindowSize()
{
return Global.Config.TargetZoomFactors[Emulator.SystemId];
}
public static void SetSoundOn(bool enable)
{
Global.Config.SoundEnabled = enable;
}
public static bool GetSoundOn()
{
return Global.Config.SoundEnabled;
}
public static bool IsPaused()
{
return (bool) GetMainFormField("EmulatorPaused");
}
public static bool IsTurbo()
{
return (bool)GetMainFormField("IsTurboing");
}
public static bool IsSeeking()
{
return (bool)GetMainFormField("IsSeeking");
}
public static void OpenRom(string path)
{
var ioa = OpenAdvancedSerializer.ParseWithLegacy(path);
Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin.MainForm.LoadRomArgs");
object o = Activator.CreateInstance(t);
t.GetField("OpenAdvanced").SetValue(o, ioa);
InvokeMainFormMethod("LoadRom", new object[] {path, o});
}
public static void Pause()
{
InvokeMainFormMethod("PauseEmulator");
}
public static void PauseAv()
{
SetMainFormField("PauseAvi", true);
}
public static void RebootCore()
{
InvokeMainFormMethod("RebootCore");
}
public static void SaveRam()
{
InvokeMainFormMethod("FlushSaveRAM");
}
public static int ScreenHeight()
{
Type t = GetMainFormField("PresentationPanel").GetType();
object o = GetMainFormField("PresentationPanel");
o = t.GetField("NativeSize").GetValue(o);
t = t.GetField("NativeSize").GetType();
return (int) t.GetField("Height").GetValue(o);
}
public static void Screenshot(string path = null)
{
if (path == null)
{
InvokeMainFormMethod("TakeScreenshot");
}
else
{
InvokeMainFormMethod("TakeScreenshot", new object[] {path});
}
}
public static void ScreenshotToClipboard()
{
InvokeMainFormMethod("TakeScreenshotToClipboard");
}
public static void SetTargetScanlineIntensity(int val)
{
Global.Config.TargetScanlineFilterIntensity = val;
}
public static void SetScreenshotOSD(bool value)
{
Global.Config.Screenshot_CaptureOSD = value;
}
public static int ScreenWidth()
{
Type t = GetMainFormField("PresentationPanel").GetType();
object o = GetMainFormField("PresentationPanel");
o = t.GetField("NativeSize").GetValue(o);
t = t.GetField("NativeSize").GetType();
return (int) t.GetField("Width").GetValue(o);
}
public static void SetWindowSize(int size)
{
if (size == 1 || size == 2 || size == 3 || size == 4 || size == 5 || size == 10)
{
Global.Config.TargetZoomFactors[Emulator.SystemId] = size;
InvokeMainFormMethod("FrameBufferResized");
Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin");
FieldInfo f = t.GetField("OSD");
object osd = f.GetValue(null);
t = f.GetType();
MethodInfo m = t.GetMethod("AddMessage");
m.Invoke(osd, new Object[] { "Window size set to " + size + "x" });
}
else
{
Console.WriteLine("Invalid window size");
}
}
public static void SpeedMode(int percent)
{
if (percent > 0 && percent < 6400)
{
InvokeMainFormMethod("ClickSpeedItem", new object[] {percent});
}
else
{
Console.WriteLine("Invalid speed value");
}
}
public static void TogglePause()
{
InvokeMainFormMethod("TogglePause");
}
public static int TransformPointX(int x)
{
var point = new System.Drawing.Point(x, 0);
Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin");
FieldInfo f = t.GetField("DisplayManager");
object displayManager = f.GetValue(null);
MethodInfo m = t.GetMethod("TransFormPoint");
point = (System.Drawing.Point)m.Invoke(displayManager, new object[] { point });
return point.X;
}
public static int TransformPointY(int y)
{
var point = new System.Drawing.Point(0, y);
Type t = clientAssembly.GetType("BizHawk.Client.EmuHawk.GlobalWin");
FieldInfo f = t.GetField("DisplayManager");
object displayManager = f.GetValue(null);
MethodInfo m = t.GetMethod("TransFormPoint");
point = (System.Drawing.Point)m.Invoke(displayManager, new object[] { point });
return point.Y;
}
public static void Unpause()
{
InvokeMainFormMethod("UnpauseEmulator");
}
public static void UnpauseAv()
{
SetMainFormField("PauseAvi", false);
}
public static int Xpos()
{
object o = GetMainFormField("DesktopLocation");
Type t = mainFormClass.GetField("DesktopLocation").GetType();
return (int)t.GetField("X").GetValue(o);
}
public static int Ypos()
{
object o = GetMainFormField("DesktopLocation");
Type t = mainFormClass.GetField("DesktopLocation").GetType();
return (int)t.GetField("Y").GetValue(o);
}
#endregion
#region Properties
@ -427,11 +774,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

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

@ -1,4 +1,4 @@
namespace BizHawk.Client.Common
namespace BizHawk.Client.ApiHawk
{
interface IPlugin
{
@ -7,6 +7,6 @@
void SaveStateCallback(string name);
void LoadStateCallback(string name);
void InputPollCallback();
void Init(IPluginAPI api);
void Init(IApiContainer api);
}
}

View File

@ -260,6 +260,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

@ -10,7 +10,7 @@ using Newtonsoft.Json;
//this file contains some cumbersome self-"serialization" in order to gain a modicum of control over what the serialized output looks like
//I don't want them to look like crufty json
namespace BizHawk.Client.EmuHawk
namespace BizHawk.Client.Common
{
public interface IOpenAdvanced
{
@ -74,7 +74,7 @@ namespace BizHawk.Client.EmuHawk
}
}
class OpenAdvanced_Libretro : IOpenAdvanced, IOpenAdvancedLibretro
public class OpenAdvanced_Libretro : IOpenAdvanced, IOpenAdvancedLibretro
{
public OpenAdvanced_Libretro()
{
@ -103,7 +103,7 @@ namespace BizHawk.Client.EmuHawk
public string CorePath { get { return token.CorePath; } set { token.CorePath = value; } }
}
class OpenAdvanced_LibretroNoGame : IOpenAdvanced, IOpenAdvancedLibretro
public class OpenAdvanced_LibretroNoGame : IOpenAdvanced, IOpenAdvancedLibretro
{
//you might think ideally we'd fetch the libretro core name from the core info inside it
//but that would involve spinning up excess libretro core instances, which probably isnt good for stability, no matter how much we wish otherwise, not to mention slow.
@ -140,7 +140,7 @@ namespace BizHawk.Client.EmuHawk
public string CorePath { get { return _corePath; } set { _corePath = value; } }
}
class OpenAdvanced_OpenRom : IOpenAdvanced
public class OpenAdvanced_OpenRom : IOpenAdvanced
{
public OpenAdvanced_OpenRom()
{}

View File

@ -1,20 +0,0 @@
using System;
using System.Collections.Generic;
namespace BizHawk.Client.Common
{
public interface IPluginAPI
{
EmulatorPluginLibrary EmuLib { get; }
GameInfoPluginLibrary GameInfoLib { get; }
GUIDrawPluginBase GUILib { get; }
JoypadPluginLibrary JoypadLib { get; }
MemoryPluginLibrary MemLib { get; }
MemoryEventsPluginLibrary MemEventsLib { get; }
MemorySavestatePluginLibrary MemStateLib { get; }
MoviePluginLibrary MovieLib { get; }
SQLPluginLibrary SQLLib { get; }
UserDataPluginLibrary UserDataLib { get; }
Dictionary<Type, PluginLibraryBase> Libraries { get; }
}
}

View File

@ -1,263 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace BizHawk.Client.Common
{
public sealed class MoviePluginLibrary : PluginLibraryBase
{
public MoviePluginLibrary() : base()
{ }
[LuaMethodExample("if ( movie.startsfromsavestate( ) ) then\r\n\tconsole.log( \"Returns whether or not the movie is a savestate-anchored movie\" );\r\nend;")]
[LuaMethod("startsfromsavestate", "Returns whether or not the movie is a savestate-anchored movie")]
public bool StartsFromSavestate()
{
return Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.StartsFromSavestate;
}
[LuaMethodExample("if ( movie.startsfromsaveram( ) ) then\r\n\tconsole.log( \"Returns whether or not the movie is a saveram-anchored movie\" );\r\nend;")]
[LuaMethod("startsfromsaveram", "Returns whether or not the movie is a saveram-anchored movie")]
public bool StartsFromSaveram()
{
return Global.MovieSession.Movie.IsActive && Global.MovieSession.Movie.StartsFromSaveRam;
}
[LuaMethodExample("local stmovfil = movie.filename( );")]
[LuaMethod("filename", "Returns the file name including path of the currently loaded movie")]
public static string Filename()
{
return Global.MovieSession.Movie.Filename;
}
[LuaMethodExample("local nlmovget = movie.getinput( 500 );")]
[LuaMethod("getinput", "Returns a table of buttons pressed on a given frame of the loaded movie")]
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;
}
[LuaMethodExample("local stmovget = movie.getinputasmnemonic( 500 );")]
[LuaMethod("getinputasmnemonic", "Returns the input of a given frame of the loaded movie in a raw inputlog string")]
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 "";
}
[LuaMethodExample("if ( movie.getreadonly( ) ) then\r\n\tconsole.log( \"Returns true if the movie is in read-only mode, false if in read+write\" );\r\nend;")]
[LuaMethod("getreadonly", "Returns true if the movie is in read-only mode, false if in read+write")]
public static bool GetReadOnly()
{
return Global.MovieSession.ReadOnly;
}
[LuaMethodExample("local ulmovget = movie.getrerecordcount();")]
[LuaMethod("getrerecordcount", "Gets the rerecord count of the current movie.")]
public static ulong GetRerecordCount()
{
return Global.MovieSession.Movie.Rerecords;
}
[LuaMethodExample("if ( movie.getrerecordcounting( ) ) then\r\n\tconsole.log( \"Returns whether or not the current movie is incrementing rerecords on loadstate\" );\r\nend;")]
[LuaMethod("getrerecordcounting", "Returns whether or not the current movie is incrementing rerecords on loadstate")]
public static bool GetRerecordCounting()
{
return Global.MovieSession.Movie.IsCountingRerecords;
}
[LuaMethodExample("if ( movie.isloaded( ) ) then\r\n\tconsole.log( \"Returns true if a movie is loaded in memory ( play, record, or finished modes ), false if not ( inactive mode )\" );\r\nend;")]
[LuaMethod("isloaded", "Returns true if a movie is loaded in memory (play, record, or finished modes), false if not (inactive mode)")]
public static bool IsLoaded()
{
return Global.MovieSession.Movie.IsActive;
}
[LuaMethodExample("local domovlen = movie.length( );")]
[LuaMethod("length", "Returns the total number of frames of the loaded movie")]
public static double Length()
{
return Global.MovieSession.Movie.FrameCount;
}
[LuaMethodExample("local stmovmod = movie.mode( );")]
[LuaMethod("mode", "Returns the mode of the current movie. Possible modes: \"PLAY\", \"RECORD\", \"FINISHED\", \"INACTIVE\"")]
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";
}
[LuaMethodExample("movie.save( \"C:\\moviename.ext\" );")]
[LuaMethod("save", "Saves the current movie to the disc. If the filename is provided (no extension or path needed), the movie is saved under the specified name to the current movie directory. The filename may contain a subdirectory, it will be created if it doesn't exist. Existing files won't get overwritten.")]
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();
}
[LuaMethodExample("movie.setreadonly( false );")]
[LuaMethod("setreadonly", "Sets the read-only state to the given value. true for read only, false for read+write")]
public static void SetReadOnly(bool readOnly)
{
Global.MovieSession.ReadOnly = readOnly;
}
[LuaMethodExample("movie.setrerecordcount( 20.0 );")]
[LuaMethod("setrerecordcount", "Sets the rerecord count of the current movie.")]
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;
}
[LuaMethodExample("movie.setrerecordcounting( true );")]
[LuaMethod("setrerecordcounting", "Sets whether or not the current movie will increment the rerecord counter on loadstate")]
public static void SetRerecordCounting(bool counting)
{
Global.MovieSession.Movie.IsCountingRerecords = counting;
}
[LuaMethodExample("movie.stop( );")]
[LuaMethod("stop", "Stops the current movie")]
public static void Stop()
{
Global.MovieSession.Movie.Stop();
}
[LuaMethodExample("local domovget = movie.getfps( );")]
[LuaMethod("getfps", "If a movie is loaded, gets the frames per second used by the movie to determine the movie length time")]
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;
}
[LuaMethodExample("local nlmovget = movie.getheader( );")]
[LuaMethod("getheader", "If a movie is active, will return the movie header as a lua table")]
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;
}
[LuaMethodExample("local nlmovget = movie.getcomments( );")]
[LuaMethod("getcomments", "If a movie is active, will return the movie comments as a lua 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;
}
[LuaMethodExample("local nlmovget = movie.getsubtitles( );")]
[LuaMethod("getsubtitles", "If a movie is active, will return the movie subtitles as a lua table")]
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;
}
}
}

View File

@ -1,29 +0,0 @@
using System.Drawing;
namespace BizHawk.Client.Common
{
public abstract class PluginLibraryBase
{
protected PluginLibraryBase() { }
protected static Color? ToColor(object o)
{
if (o == null)
{
return null;
}
if (o.GetType() == typeof(double))
{
return Color.FromArgb((int)(long)(double)o);
}
if (o.GetType() == typeof(string))
{
return Color.FromName(o.ToString());
}
return null;
}
}
}

View File

@ -0,0 +1,32 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using BizHawk.Client.ApiHawk;
namespace BizHawk.Client.EmuHawk
{
public sealed class ApiContainer : IApiContainer
{
public IComm Comm => (IComm)Libraries[typeof(CommApi)];
public IEmu Emu => (IEmu)Libraries[typeof(EmuApi)];
public IGameInfo GameInfo => (IGameInfo)Libraries[typeof(GameInfoApi)];
public IGui Gui => (IGui)Libraries[typeof(GuiApi)];
public IInput Input => (IInput)Libraries[typeof(InputApi)];
public IJoypad Joypad => (IJoypad)Libraries[typeof(JoypadApi)];
public IMem Mem => (IMem)Libraries[typeof(MemApi)];
public IMemEvents MemEvents => (IMemEvents)Libraries[typeof(MemEventsApi)];
public IMemorySaveState MemorySaveState => (IMemorySaveState)Libraries[typeof(MemorySaveStateApi)];
public IMovie Movie => (IMovie)Libraries[typeof(MovieApi)];
public ISaveState SaveState => (ISaveState)Libraries[typeof(SaveStateApi)];
public ISql Sql => (ISql)Libraries[typeof(SqlApi)];
public ITool Tool => (ITool)Libraries[typeof(ToolApi)];
public IUserData UserData => (IUserData)Libraries[typeof(UserDataApi)];
public Dictionary<Type, IExternalApi> Libraries { get; set; }
public ApiContainer(Dictionary<Type, IExternalApi> libs)
{
Libraries = libs;
}
}
}

View File

@ -2,7 +2,7 @@
using System.ComponentModel;
using BizHawk.Emulation.Common;
using BizHawk.Client.Common;
using BizHawk.Client.ApiHawk;
using System.Text;
using System.Collections.Generic;
using System.Net.Http;
@ -11,7 +11,7 @@ using System.Windows.Forms;
namespace BizHawk.Client.EmuHawk
{
public sealed class CommunicationPluginLibrary : PluginLibraryBase
public sealed class CommApi : IComm
{
[RequiredService]
private IEmulator Emulator { get; set; }
@ -19,7 +19,7 @@ namespace BizHawk.Client.EmuHawk
[RequiredService]
private IVideoProvider VideoProvider { get; set; }
public CommunicationPluginLibrary() : base()
public CommApi() : base()
{ }
public string SocketServerScreenShot()

View File

@ -5,44 +5,47 @@ using System.Drawing.Imaging;
using System.Windows.Forms;
using System.IO;
using BizHawk.Client.ApiHawk;
using BizHawk.Emulation.Common;
namespace BizHawk.Client.Common
namespace BizHawk.Client.EmuHawk
{
public abstract class GUIDrawPluginBase : PluginLibraryBase
public sealed class GuiApi : IGui
{
[RequiredService]
protected IEmulator Emulator { get; set; }
public GUIDrawPluginBase() : base()
{ }
public bool HasGUISurface = false;
protected Color _defaultForeground = Color.White;
protected Color? _defaultBackground;
protected Color? _defaultTextBackground = Color.FromArgb(128, 0, 0, 0);
protected int _defaultPixelFont = 1; // gens
protected Padding _padding = new Padding(0);
protected ImageAttributes _attributes = new ImageAttributes();
private IEmulator Emulator { get; set; }
private Color _defaultForeground = Color.White;
private Color? _defaultBackground;
private Color? _defaultTextBackground = Color.FromArgb(128, 0, 0, 0);
private int _defaultPixelFont = 1; // gens
private Padding _padding = new Padding(0);
private ImageAttributes _attributes = new ImageAttributes();
private System.Drawing.Drawing2D.CompositingMode _compositingMode = System.Drawing.Drawing2D.CompositingMode.SourceOver;
public virtual void ToggleCompositingMode()
public GuiApi()
{ }
private DisplaySurface _GUISurface = null;
public bool HasGUISurface => _GUISurface != null;
#region Gui API
public void ToggleCompositingMode()
{
_compositingMode = 1 - _compositingMode;
}
public virtual ImageAttributes GetAttributes()
public ImageAttributes GetAttributes()
{
return _attributes;
}
public virtual void SetAttributes(ImageAttributes a)
public void SetAttributes(ImageAttributes a)
{
_attributes = a;
}
#region Gui API
public virtual void Dispose()
public void Dispose()
{
foreach (var brush in _solidBrushes.Values)
{
@ -55,16 +58,35 @@ namespace BizHawk.Client.Common
}
}
public abstract void DrawNew(string name, bool? clear = true);
public abstract void DrawFinish();
public void DrawNew(string name, bool? clear = true)
{
try
{
DrawFinish();
_GUISurface = GlobalWin.DisplayManager.LockLuaSurface(name, clear ?? true);
}
catch (InvalidOperationException ex)
{
Console.WriteLine(ex.ToString());
}
}
public void DrawFinish()
{
if (_GUISurface != null)
{
GlobalWin.DisplayManager.UnlockLuaSurface(_GUISurface);
}
_GUISurface = null;
}
#endregion
#region Helpers
protected readonly Dictionary<string, Image> _imageCache = new Dictionary<string, Image>();
protected readonly Dictionary<Color, SolidBrush> _solidBrushes = new Dictionary<Color, SolidBrush>();
protected readonly Dictionary<Color, Pen> _pens = new Dictionary<Color, Pen>();
protected SolidBrush GetBrush(Color color)
private readonly Dictionary<string, Image> _imageCache = new Dictionary<string, Image>();
private readonly Dictionary<Color, SolidBrush> _solidBrushes = new Dictionary<Color, SolidBrush>();
private readonly Dictionary<Color, Pen> _pens = new Dictionary<Color, Pen>();
private SolidBrush GetBrush(Color color)
{
SolidBrush b;
if (!_solidBrushes.TryGetValue(color, out b))
@ -76,7 +98,7 @@ namespace BizHawk.Client.Common
return b;
}
protected Pen GetPen(Color color)
private Pen GetPen(Color color)
{
Pen p;
if (!_pens.TryGetValue(color, out p))
@ -88,7 +110,22 @@ namespace BizHawk.Client.Common
return p;
}
protected abstract Graphics GetGraphics();
private Graphics GetGraphics()
{
var g = _GUISurface == null ? Graphics.FromImage(new Bitmap(1,1)) : _GUISurface.GetGraphics();
// we don't like CoreComm, right? Someone should find a different way to do this then.
var tx = Emulator.CoreComm.ScreenLogicalOffsetX;
var ty = Emulator.CoreComm.ScreenLogicalOffsetY;
if (tx != 0 || ty != 0)
{
var transform = g.Transform;
transform.Translate(-tx, -ty);
g.Transform = transform;
}
return g;
}
public void SetPadding(int all)
{
_padding = new Padding(all);
@ -97,7 +134,7 @@ namespace BizHawk.Client.Common
{
_padding = new Padding(x / 2, y / 2, x / 2 + x & 1, y / 2 + y & 1);
}
public void SetPadding(int l,int t,int r, int b)
public void SetPadding(int l, int t, int r, int b)
{
_padding = new Padding(l, t, r, b);
}
@ -107,11 +144,21 @@ namespace BizHawk.Client.Common
}
#endregion
public abstract void AddMessage(string message);
public void AddMessage(string message)
{
GlobalWin.OSD.AddMessage(message);
}
public abstract void ClearGraphics();
public void ClearGraphics()
{
_GUISurface.Clear();
DrawFinish();
}
public abstract void ClearText();
public void ClearText()
{
GlobalWin.OSD.ClearGUIText();
}
public void SetDefaultForegroundColor(Color color)
{
@ -352,7 +399,7 @@ namespace BizHawk.Client.Common
{
using (var g = GetGraphics())
{
g.CompositingMode = _compositingMode;
g.CompositingMode = _compositingMode;
g.DrawLine(GetPen(color ?? _defaultForeground), x1, y1, x2, y2);
}
}
@ -424,12 +471,13 @@ namespace BizHawk.Client.Common
var bg = background ?? _defaultBackground;
if (bg.HasValue)
{
g.FillRectangle(GetBrush(bg.Value), x + 1, y + 1, Math.Max(w - 1, 0), Math.Max(h - 1, 0)); }
g.FillRectangle(GetBrush(bg.Value), x + 1, y + 1, Math.Max(w - 1, 0), Math.Max(h - 1, 0));
}
}
}
public void DrawString(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, int? fontsize = null,
string fontfamily = null, string fontstyle = null, string horizalign = null, string vertalign = null)
public void DrawString(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, int? fontsize = null,
string fontfamily = null, string fontstyle = null, string horizalign = null, string vertalign = null)
{
using (var g = GetGraphics())
{
@ -508,7 +556,7 @@ namespace BizHawk.Client.Common
{
for (var yd = -1; yd <= 1; yd++)
{
g.DrawString(message, font, GetBrush(bg.Value), x+xd, y+yd);
g.DrawString(message, font, GetBrush(bg.Value), x + xd, y + yd);
}
}
}
@ -522,7 +570,86 @@ namespace BizHawk.Client.Common
}
}
public abstract void DrawText(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, string fontfamily = null);
public abstract void Text(int x, int y, string message, Color? forecolor = null, string anchor = null);
public void DrawText(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, string fontfamily = null)
{
using (var g = GetGraphics())
{
try
{
var index = 0;
if (string.IsNullOrEmpty(fontfamily))
{
index = _defaultPixelFont;
}
else
{
switch (fontfamily)
{
case "fceux":
case "0":
index = 0;
break;
case "gens":
case "1":
index = 1;
break;
default:
Console.WriteLine($"Unable to find font family: {fontfamily}");
return;
}
}
var f = new StringFormat(StringFormat.GenericTypographic)
{
FormatFlags = StringFormatFlags.MeasureTrailingSpaces
};
var font = new Font(GlobalWin.DisplayManager.CustomFonts.Families[index], 8, FontStyle.Regular, GraphicsUnit.Pixel);
Size sizeOfText = g.MeasureString(message, font, 0, f).ToSize();
var rect = new Rectangle(new Point(x, y), sizeOfText + new Size(1, 0));
if (backcolor.HasValue) g.FillRectangle(GetBrush(backcolor.Value), rect);
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
g.DrawString(message, font, GetBrush(forecolor ?? _defaultForeground), x, y);
}
catch (Exception)
{
return;
}
}
}
public void Text(int x, int y, string message, Color? forecolor = null, string anchor = null)
{
var a = 0;
if (!string.IsNullOrEmpty(anchor))
{
switch (anchor)
{
case "0":
case "topleft":
a = 0;
break;
case "1":
case "topright":
a = 1;
break;
case "2":
case "bottomleft":
a = 2;
break;
case "3":
case "bottomright":
a = 3;
break;
}
}
else
{
x -= Emulator.CoreComm.ScreenLogicalOffsetX;
y -= Emulator.CoreComm.ScreenLogicalOffsetY;
}
GlobalWin.OSD.AddGUIText(message, x, y, Color.Black, forecolor ?? Color.White, a);
}
}
}

View File

@ -3,13 +3,14 @@ using System.Linq;
using System.Collections.Generic;
using System.Windows.Forms;
using BizHawk.Client.ApiHawk;
using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk
{
public sealed class InputPluginLibrary : PluginLibraryBase
public sealed class InputApi : IInput
{
public InputPluginLibrary() : base()
public InputApi() : base()
{ }
public Dictionary<string,bool> Get()

View File

@ -0,0 +1,52 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using BizHawk.Common.ReflectionExtensions;
using BizHawk.Emulation.Common;
using BizHawk.Client.ApiHawk;
namespace BizHawk.Client.EmuHawk
{
public static class ApiManager
{
private static ApiContainer container;
private static void Register(IEmulatorServiceProvider serviceProvider)
{
// Register external apis
var libs = Assembly
.Load("BizHawk.Client.ApiHawk")
.GetTypes()
.Where(t => typeof(IExternalApi).IsAssignableFrom(t))
.Where(t => t.IsSealed)
.Where(t => ServiceInjector.IsAvailable(serviceProvider, t))
.ToList();
libs.AddRange(
Assembly
.GetAssembly(typeof(ApiContainer))
.GetTypes()
.Where(t => typeof(IExternalApi).IsAssignableFrom(t))
.Where(t => t.IsSealed)
.Where(t => ServiceInjector.IsAvailable(serviceProvider, t)));
foreach (var lib in libs)
{
var instance = (IExternalApi)Activator.CreateInstance(lib);
ServiceInjector.UpdateServices(serviceProvider, instance);
Libraries.Add(lib, instance);
}
container = new ApiContainer(Libraries);
GlobalWin.ApiProvider = new BasicApiProvider(container);
}
private static readonly Dictionary<Type, IExternalApi> Libraries = new Dictionary<Type, IExternalApi>();
public static void Restart(IEmulatorServiceProvider newServiceProvider)
{
Libraries.Clear();
Register(newServiceProvider);
}
}
}

View File

@ -2,13 +2,13 @@
using System.Collections.Generic;
using System.IO;
using BizHawk.Client.Common;
using BizHawk.Client.ApiHawk;
namespace BizHawk.Client.EmuHawk
{
public sealed class SavestatePluginibrary : PluginLibraryBase
public sealed class SaveStateApi : ISaveState
{
public SavestatePluginibrary() : base()
public SaveStateApi() : base()
{ }
public void Load(string path)

View File

@ -0,0 +1,162 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Client.ApiHawk;
using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk
{
public sealed class ToolApi : ITool
{
private class ToolStatic
{
public Type GetTool(string name)
{
var toolType = ReflectionUtil.GetTypeByName(name)
.FirstOrDefault(x => typeof(IToolForm).IsAssignableFrom(x) && !x.IsInterface);
if (toolType != null)
{
GlobalWin.Tools.Load(toolType);
}
var selectedTool = GlobalWin.Tools.AvailableTools
.FirstOrDefault(tool => tool.GetType().Name.ToLower() == name.ToLower());
if (selectedTool != null)
{
return selectedTool;
}
return null;
}
public object CreateInstance(string name)
{
var possibleTypes = ReflectionUtil.GetTypeByName(name);
if (possibleTypes.Any())
{
return Activator.CreateInstance(possibleTypes.First());
}
return null;
}
public static void OpenCheats()
{
GlobalWin.Tools.Load<Cheats>();
}
public static void OpenHexEditor()
{
GlobalWin.Tools.Load<HexEditor>();
}
public static void OpenRamWatch()
{
GlobalWin.Tools.LoadRamWatch(loadDialog: true);
}
public static void OpenRamSearch()
{
GlobalWin.Tools.Load<RamSearch>();
}
public static void OpenTasStudio()
{
GlobalWin.Tools.Load<TAStudio>();
}
public static void OpenToolBox()
{
GlobalWin.Tools.Load<ToolBox>();
}
public static void OpenTraceLogger()
{
GlobalWin.Tools.Load<TraceLogger>();
}
}
[RequiredService]
private static IEmulator Emulator { get; set; }
[RequiredService]
private static IVideoProvider VideoProvider { get; set; }
public ToolApi()
{ }
public Type GetTool(string name)
{
var toolType = ReflectionUtil.GetTypeByName(name)
.FirstOrDefault(x => typeof(IToolForm).IsAssignableFrom(x) && !x.IsInterface);
if (toolType != null)
{
GlobalWin.Tools.Load(toolType);
}
var selectedTool = GlobalWin.Tools.AvailableTools
.FirstOrDefault(tool => tool.GetType().Name.ToLower() == name.ToLower());
if (selectedTool != null)
{
return selectedTool;
}
return null;
}
public object CreateInstance(string name)
{
var possibleTypes = ReflectionUtil.GetTypeByName(name);
if (possibleTypes.Any())
{
return Activator.CreateInstance(possibleTypes.First());
}
return null;
}
public void OpenCheats()
{
ToolStatic.OpenCheats();
}
public void OpenHexEditor()
{
ToolStatic.OpenHexEditor();
}
public void OpenRamWatch()
{
ToolStatic.OpenRamWatch();
}
public void OpenRamSearch()
{
ToolStatic.OpenRamSearch();
}
public void OpenTasStudio()
{
ToolStatic.OpenTasStudio();
}
public void OpenToolBox()
{
ToolStatic.OpenToolBox();
}
public void OpenTraceLogger()
{
ToolStatic.OpenTraceLogger();
}
}
}

View File

@ -658,9 +658,14 @@
</Compile>
<Compile Include="GLManager.cs" />
<Compile Include="GlobalWin.cs" />
<Compile Include="Plugins\Example\Ecco2AssistantPlugin.cs" />
<Compile Include="Plugins\Libraries\PluginLibrary.Client.cs" />
<Compile Include="Plugins\Libraries\PluginLibrary.GUI.cs" />
<Compile Include="Api\Example\Ecco2AssistantPlugin.cs" />
<Compile Include="Api\ApiContainer.cs" />
<Compile Include="Api\Libraries\ToolApi.cs" />
<Compile Include="Api\Libraries\GuiApi.cs" />
<Compile Include="Api\Libraries\InputApi.cs" />
<Compile Include="Api\Libraries\SaveStateAPI.cs" />
<Compile Include="Api\Libraries\PluginLibrary.cs" />
<Compile Include="Api\Libraries\CommApi.cs" />
<!--<Compile Include="Input\GamePad.cs" Condition=" '$(OS)' == 'Windows_NT' " />-->
<Compile Include="Input\GamePad.cs" />
<Compile Include="Input\GamePad360.cs" />
@ -734,7 +739,6 @@
<Compile Include="NameStateForm.Designer.cs">
<DependentUpon>NameStateForm.cs</DependentUpon>
</Compile>
<Compile Include="OpenAdvanced.cs" />
<Compile Include="OpenAdvancedChooser.cs">
<SubType>Form</SubType>
</Compile>
@ -747,10 +751,6 @@
<Compile Include="PlatformChooser.Designer.cs">
<DependentUpon>PlatformChooser.cs</DependentUpon>
</Compile>
<Compile Include="Plugins\Libraries\PluginLibrary.Input.cs" />
<Compile Include="Plugins\Libraries\PluginLibrary.Savestate.cs" />
<Compile Include="Plugins\PluginAPI.cs" />
<Compile Include="Plugins\Libraries\PluginLibrary.cs" />
<Compile Include="PresentationPanel.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
@ -1888,7 +1888,6 @@
<None Include="Resources\MoveTop.png" />
<None Include="Resources\MoveBottom.png" />
<None Include="Resources\MoveTop.bmp" />
<Compile Include="Plugins\Libraries\PluginLibrary.Communications.cs" />
<None Include="Resources\ZXSpectrumKeyboard.bmp" />
<None Include="images\WSW.png" />
<None Include="images\WNW.png" />

View File

@ -1,4 +1,5 @@
using BizHawk.Bizware.BizwareGL;
using BizHawk.Client.ApiHawk;
// ReSharper disable StyleCop.SA1401
namespace BizHawk.Client.EmuHawk
@ -7,7 +8,7 @@ namespace BizHawk.Client.EmuHawk
{
public static MainForm MainForm;
public static ToolManager Tools;
public static PluginLibrary Plugins;
public static BasicApiProvider ApiProvider;
/// <summary>
/// the IGL to be used for rendering

View File

@ -252,8 +252,6 @@ namespace BizHawk.Client.EmuHawk
GlobalWin.Sound.StartSound();
InputManager.RewireInputChain();
GlobalWin.Tools = new ToolManager(this);
GlobalWin.Plugins = new PluginLibrary(Emulator.ServiceProvider);
GlobalWin.Plugins.Load(new Ecco2AssistantPlugin());
RewireSound();
// Workaround for windows, location is -32000 when minimized, if they close it during this time, that's what gets saved
@ -2937,7 +2935,6 @@ namespace BizHawk.Client.EmuHawk
{
GlobalWin.Tools.LuaConsole.LuaImp.CallFrameBeforeEvent();
}
GlobalWin.Plugins.CallFrameBeforeEvent();
if (IsTurboing)
{
@ -3024,7 +3021,6 @@ namespace BizHawk.Client.EmuHawk
{
GlobalWin.Tools.LuaConsole.LuaImp.CallFrameAfterEvent();
}
GlobalWin.Plugins.CallFrameAfterEvent();
if (IsTurboing)
{
@ -3798,7 +3794,7 @@ namespace BizHawk.Client.EmuHawk
}
GlobalWin.Tools.Restart();
GlobalWin.Plugins.Restart(Emulator.ServiceProvider);
ApiManager.Restart(Emulator.ServiceProvider);
if (Global.Config.LoadCheatFileByGame)
{
@ -3846,7 +3842,7 @@ namespace BizHawk.Client.EmuHawk
}
}
ClientApi.OnRomLoaded();
ClientApi.OnRomLoaded(Emulator);
return true;
}
else
@ -3857,10 +3853,11 @@ namespace BizHawk.Client.EmuHawk
// The ROM has been loaded by a recursive invocation of the LoadROM method.
if (!(Emulator is NullEmulator))
{
ClientApi.OnRomLoaded();
ClientApi.OnRomLoaded(Emulator);
return true;
}
ClientApi.UpdateEmulatorAndVP(Emulator);
HandlePlatformMenus();
_stateSlots.Clear();
UpdateStatusSlots();
@ -3950,6 +3947,7 @@ namespace BizHawk.Client.EmuHawk
var coreComm = CreateCoreComm();
CoreFileProvider.SyncCoreCommInputSignals(coreComm);
Emulator = new NullEmulator(coreComm, Global.Config.GetCoreSettings<NullEmulator>());
ClientApi.UpdateEmulatorAndVP(Emulator);
Global.ActiveController = new Controller(NullController.Instance.Definition);
Global.AutoFireController = _autofireNullControls;
RewireSound();
@ -3972,7 +3970,7 @@ namespace BizHawk.Client.EmuHawk
Global.Game = GameInfo.NullInstance;
GlobalWin.Tools.Restart();
GlobalWin.Plugins.Restart(Emulator.ServiceProvider);
ApiManager.Restart(Emulator.ServiceProvider);
RewireSound();
Text = "BizHawk" + (VersionInfo.DeveloperBuild ? " (interim) " : "");
HandlePlatformMenus();
@ -4068,7 +4066,6 @@ namespace BizHawk.Client.EmuHawk
{
GlobalWin.Tools.LuaConsole.LuaImp.CallLoadStateEvent(userFriendlyStateName);
}
GlobalWin.Plugins.CallLoadStateEvent(userFriendlyStateName);
SetMainformMovieInfo();
GlobalWin.Tools.UpdateToolsBefore(fromLua);
@ -4198,7 +4195,6 @@ namespace BizHawk.Client.EmuHawk
{
GlobalWin.Tools.LuaConsole.LuaImp.CallSaveStateEvent(quickSlotName);
}
GlobalWin.Plugins.CallSaveStateEvent(quickSlotName);
}
private void SaveStateAs()

View File

@ -1,351 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk
{
public sealed class EmuHawkPluginLibrary : PluginLibraryBase
{
[RequiredService]
private IEmulator Emulator { get; set; }
[RequiredService]
private IVideoProvider VideoProvider { get; set; }
private readonly Dictionary<int, string> _filterMappings = new Dictionary<int, string>
{
{ 0, "None" },
{ 1, "x2SAI" },
{ 2, "SuperX2SAI" },
{ 3, "SuperEagle" },
{ 4, "Scanlines" },
};
public EmuHawkPluginLibrary() : base()
{ }
public void CloseEmulator()
{
GlobalWin.MainForm.CloseEmulator();
}
public void CloseEmulatorWithCode(int exitCode)
{
GlobalWin.MainForm.CloseEmulator(exitCode);
}
public static int BorderHeight()
{
var point = new System.Drawing.Point(0, 0);
return GlobalWin.DisplayManager.TransformPoint(point).Y;
}
public static int BorderWidth()
{
var point = new System.Drawing.Point(0, 0);
return GlobalWin.DisplayManager.TransformPoint(point).X;
}
public int BufferHeight()
{
return VideoProvider.BufferHeight;
}
public int BufferWidth()
{
return VideoProvider.BufferWidth;
}
public void ClearAutohold()
{
GlobalWin.MainForm.ClearHolds();
}
public static void CloseRom()
{
GlobalWin.MainForm.CloseRom();
}
public void EnableRewind(bool enabled)
{
GlobalWin.MainForm.EnableRewind(enabled);
}
public void FrameSkip(int numFrames)
{
if (numFrames > 0)
{
Global.Config.FrameSkip = numFrames;
GlobalWin.MainForm.FrameSkipMessage();
}
else
{
Console.WriteLine("Invalid frame skip value");
}
}
public static int GetTargetScanlineIntensity()
{
return Global.Config.TargetScanlineFilterIntensity;
}
public int GetWindowSize()
{
return Global.Config.TargetZoomFactors[Emulator.SystemId];
}
public static void SetGameExtraPadding(int left, int top, int right, int bottom)
{
GlobalWin.DisplayManager.GameExtraPadding = new System.Windows.Forms.Padding(left, top, right, bottom);
GlobalWin.MainForm.FrameBufferResized();
}
public static void SetSoundOn(bool enable)
{
Global.Config.SoundEnabled = enable;
}
public static bool GetSoundOn()
{
return Global.Config.SoundEnabled;
}
public static void SetClientExtraPadding(int left, int top, int right, int bottom)
{
GlobalWin.DisplayManager.ClientExtraPadding = new System.Windows.Forms.Padding(left, top, right, bottom);
GlobalWin.MainForm.FrameBufferResized();
}
public static bool IsPaused()
{
return GlobalWin.MainForm.EmulatorPaused;
}
public static bool IsTurbo()
{
return GlobalWin.MainForm.IsTurboing;
}
public static bool IsSeeking()
{
return GlobalWin.MainForm.IsSeeking;
}
public static void OpenCheats()
{
GlobalWin.Tools.Load<Cheats>();
}
public static void OpenHexEditor()
{
GlobalWin.Tools.Load<HexEditor>();
}
public static void OpenRamWatch()
{
GlobalWin.Tools.LoadRamWatch(loadDialog: true);
}
public static void OpenRamSearch()
{
GlobalWin.Tools.Load<RamSearch>();
}
public static void OpenRom(string path)
{
var ioa = OpenAdvancedSerializer.ParseWithLegacy(path);
GlobalWin.MainForm.LoadRom(path, new MainForm.LoadRomArgs { OpenAdvanced = ioa });
}
public static void OpenTasStudio()
{
GlobalWin.Tools.Load<TAStudio>();
}
public static void OpenToolBox()
{
GlobalWin.Tools.Load<ToolBox>();
}
public static void OpenTraceLogger()
{
GlobalWin.Tools.Load<TraceLogger>();
}
public static void Pause()
{
GlobalWin.MainForm.PauseEmulator();
}
public static void PauseAv()
{
GlobalWin.MainForm.PauseAvi = true;
}
public static void RebootCore()
{
((LuaConsole)GlobalWin.Tools.Get<LuaConsole>()).LuaImp.IsRebootingCore = true;
GlobalWin.MainForm.RebootCore();
((LuaConsole)GlobalWin.Tools.Get<LuaConsole>()).LuaImp.IsRebootingCore = false;
}
public static int ScreenHeight()
{
return GlobalWin.MainForm.PresentationPanel.NativeSize.Height;
}
public static void Screenshot(string path = null)
{
if (path == null)
{
GlobalWin.MainForm.TakeScreenshot();
}
else
{
GlobalWin.MainForm.TakeScreenshot(path);
}
}
public static void ScreenshotToClipboard()
{
GlobalWin.MainForm.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()
{
return GlobalWin.MainForm.PresentationPanel.NativeSize.Width;
}
public void SetWindowSize(int size)
{
if (size == 1 || size == 2 || size == 3 || size == 4 || size == 5 || size == 10)
{
Global.Config.TargetZoomFactors[Emulator.SystemId] = size;
GlobalWin.MainForm.FrameBufferResized();
GlobalWin.OSD.AddMessage("Window size set to " + size + "x");
}
else
{
Console.WriteLine("Invalid window size");
}
}
public void SpeedMode(int percent)
{
if (percent > 0 && percent < 6400)
{
GlobalWin.MainForm.ClickSpeedItem(percent);
}
else
{
Console.WriteLine("Invalid speed value");
}
}
public static void TogglePause()
{
GlobalWin.MainForm.TogglePause();
}
public static int TransformPointX(int x)
{
var point = new System.Drawing.Point(x, 0);
return GlobalWin.DisplayManager.TransformPoint(point).X;
}
public static int TransformPointY(int y)
{
var point = new System.Drawing.Point(0, y);
return GlobalWin.DisplayManager.TransformPoint(point).Y;
}
public static void Unpause()
{
GlobalWin.MainForm.UnpauseEmulator();
}
public static void UnpauseAv()
{
GlobalWin.MainForm.PauseAvi = false;
}
public static int Xpos()
{
return GlobalWin.MainForm.DesktopLocation.X;
}
public static int Ypos()
{
return GlobalWin.MainForm.DesktopLocation.Y;
}
public List<string> GetAvailableTools()
{
var tools = GlobalWin.Tools.AvailableTools.ToList();
var t = new List<string>(tools.Count);
for (int i = 0; i < tools.Count; i++)
{
t[i] = tools[i].Name.ToLower();
}
return t;
}
public Type GetTool(string name)
{
var toolType = ReflectionUtil.GetTypeByName(name)
.FirstOrDefault(x => typeof(IToolForm).IsAssignableFrom(x) && !x.IsInterface);
if (toolType != null)
{
GlobalWin.Tools.Load(toolType);
}
var selectedTool = GlobalWin.Tools.AvailableTools
.FirstOrDefault(tool => tool.GetType().Name.ToLower() == name.ToLower());
if (selectedTool != null)
{
return selectedTool;
}
return null;
}
public object CreateInstance(string name)
{
var possibleTypes = ReflectionUtil.GetTypeByName(name);
if (possibleTypes.Any())
{
return Activator.CreateInstance(possibleTypes.First());
}
return null;
}
public void DisplayMessages(bool value)
{
Global.Config.DisplayMessages = value;
}
public void SaveRam()
{
GlobalWin.MainForm.FlushSaveRAM();
}
}
}

View File

@ -1,162 +0,0 @@
using System;
using System.Drawing;
using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk
{
public sealed class GUIPluginLibrary : GUIDrawPluginBase
{
public GUIPluginLibrary() : base()
{ }
private DisplaySurface _GUISurface = null;
#region Gui API
public override void DrawNew(string name, bool? clear = true)
{
try
{
DrawFinish();
_GUISurface = GlobalWin.DisplayManager.LockLuaSurface(name, clear ?? true);
HasGUISurface = (_GUISurface != null);
}
catch (InvalidOperationException ex)
{
Console.WriteLine(ex.ToString());
}
}
public override void DrawFinish()
{
if (_GUISurface != null)
{
GlobalWin.DisplayManager.UnlockLuaSurface(_GUISurface);
}
_GUISurface = null;
HasGUISurface = false;
}
#endregion
#region Helpers
protected override Graphics GetGraphics()
{
var g = _GUISurface == null ? Graphics.FromImage(new Bitmap(1,1)) : _GUISurface.GetGraphics();
// we don't like CoreComm, right? Someone should find a different way to do this then.
var tx = Emulator.CoreComm.ScreenLogicalOffsetX;
var ty = Emulator.CoreComm.ScreenLogicalOffsetY;
if (tx != 0 || ty != 0)
{
var transform = g.Transform;
transform.Translate(-tx, -ty);
g.Transform = transform;
}
return g;
}
#endregion
public override void AddMessage(string message)
{
GlobalWin.OSD.AddMessage(message);
}
public override void ClearGraphics()
{
_GUISurface.Clear();
DrawFinish();
}
public override void ClearText()
{
GlobalWin.OSD.ClearGUIText();
}
public override void DrawText(int x, int y, string message, Color? forecolor = null, Color? backcolor = null, string fontfamily = null)
{
using (var g = GetGraphics())
{
try
{
var index = 0;
if (string.IsNullOrEmpty(fontfamily))
{
index = _defaultPixelFont;
}
else
{
switch (fontfamily)
{
case "fceux":
case "0":
index = 0;
break;
case "gens":
case "1":
index = 1;
break;
default:
Console.WriteLine($"Unable to find font family: {fontfamily}");
return;
}
}
var f = new StringFormat(StringFormat.GenericTypographic)
{
FormatFlags = StringFormatFlags.MeasureTrailingSpaces
};
var font = new Font(GlobalWin.DisplayManager.CustomFonts.Families[index], 8, FontStyle.Regular, GraphicsUnit.Pixel);
Size sizeOfText = g.MeasureString(message, font, 0, f).ToSize();
var rect = new Rectangle(new Point(x, y), sizeOfText + new Size(1, 0));
if (backcolor.HasValue) g.FillRectangle(GetBrush(backcolor.Value), rect);
g.TextRenderingHint = System.Drawing.Text.TextRenderingHint.SingleBitPerPixelGridFit;
g.DrawString(message, font, GetBrush(forecolor ?? _defaultForeground), x, y);
}
catch (Exception)
{
return;
}
}
}
public override void Text(int x, int y, string message, Color? forecolor = null, string anchor = null)
{
var a = 0;
if (!string.IsNullOrEmpty(anchor))
{
switch (anchor)
{
case "0":
case "topleft":
a = 0;
break;
case "1":
case "topright":
a = 1;
break;
case "2":
case "bottomleft":
a = 2;
break;
case "3":
case "bottomright":
a = 3;
break;
}
}
else
{
x -= Emulator.CoreComm.ScreenLogicalOffsetX;
y -= Emulator.CoreComm.ScreenLogicalOffsetY;
}
GlobalWin.OSD.AddGUIText(message, x, y, Color.Black, forecolor ?? Color.White, a);
}
}
}

View File

@ -1,125 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using BizHawk.Common.ReflectionExtensions;
using BizHawk.Emulation.Common;
using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk
{
public class PluginLibrary
{
// public LuaDocumentation Docs { get; }
private void Register(IEmulatorServiceProvider serviceProvider)
{
// Docs.Clear();
// Register lua libraries
var libs = Assembly
.Load("BizHawk.Client.Common")
.GetTypes()
.Where(t => typeof(PluginLibraryBase).IsAssignableFrom(t))
.Where(t => t.IsSealed)
.Where(t => ServiceInjector.IsAvailable(serviceProvider, t))
.ToList();
libs.AddRange(
Assembly
.GetAssembly(typeof(PluginLibrary))
.GetTypes()
.Where(t => typeof(PluginLibraryBase).IsAssignableFrom(t))
.Where(t => t.IsSealed)
.Where(t => ServiceInjector.IsAvailable(serviceProvider, t)));
foreach (var lib in libs)
{
var instance = (PluginLibraryBase)Activator.CreateInstance(lib);
ServiceInjector.UpdateServices(serviceProvider, instance);
Libraries.Add(lib, instance);
}
}
public PluginLibrary(IEmulatorServiceProvider serviceProvider)
{
Register(serviceProvider);
}
private readonly Dictionary<Type, PluginLibraryBase> Libraries = new Dictionary<Type, PluginLibraryBase>();
public List<PluginBase> PluginList { get; } = new List<PluginBase>();
public IEnumerable<PluginBase> RunningPlugins
{
get { return PluginList.Where(plug => plug.Enabled); }
}
// private FormsPluginLibrary FormsLibrary => (FormsLuaLibrary)Libraries[typeof(FormsLuaLibrary)];
// private EmulatorPluginLibrary EmuPluginLibrary => (EmulatorPluginLibrary)Libraries[typeof(EmulatorPluginLibrary)];
private GUIPluginLibrary GuiLibrary => (GUIPluginLibrary)Libraries[typeof(GUIPluginLibrary)];
public void Restart(IEmulatorServiceProvider newServiceProvider)
{
Libraries.Clear();
Register(newServiceProvider);
foreach (var plugin in PluginList)
{
plugin.Init(new PluginAPI(Libraries));
}
}
public void StartPluginDrawing()
{
if (PluginList.Any() && !GuiLibrary.HasGUISurface)
{
GuiLibrary.DrawNew("emu");
}
}
public void EndPluginDrawing()
{
if (PluginList.Any())
{
GuiLibrary.DrawFinish();
}
}
public void CallSaveStateEvent(string name)
{
foreach (var plugin in RunningPlugins) plugin.SaveStateCallback(name);
}
public void CallLoadStateEvent(string name)
{
foreach (var plugin in RunningPlugins) plugin.LoadStateCallback(name);
}
public void CallFrameBeforeEvent()
{
StartPluginDrawing();
foreach (var plugin in RunningPlugins) plugin.PreFrameCallback();
}
public void CallFrameAfterEvent()
{
foreach (var plugin in RunningPlugins) plugin.PostFrameCallback();
EndPluginDrawing();
}
public void CallExitEvent()
{
foreach (var plugin in RunningPlugins) plugin.ExitCallback();
}
public void Close()
{
GuiLibrary.Dispose();
}
public void Load(PluginBase plugin)
{
plugin.Init(new PluginAPI(Libraries));
PluginList.Add(plugin);
}
}
}

View File

@ -1,28 +0,0 @@
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;
using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk
{
public sealed class PluginAPI : IPluginAPI
{
public EmulatorPluginLibrary EmuLib => (EmulatorPluginLibrary)Libraries[typeof(EmulatorPluginLibrary)];
public GameInfoPluginLibrary GameInfoLib => (GameInfoPluginLibrary)Libraries[typeof(GameInfoPluginLibrary)];
public GUIDrawPluginBase GUILib => (GUIDrawPluginBase)Libraries[typeof(GUIPluginLibrary)];
public JoypadPluginLibrary JoypadLib => (JoypadPluginLibrary)Libraries[typeof(JoypadPluginLibrary)];
public MemoryPluginLibrary MemLib => (MemoryPluginLibrary)Libraries[typeof(MemoryPluginLibrary)];
public MemoryEventsPluginLibrary MemEventsLib => (MemoryEventsPluginLibrary)Libraries[typeof(MemoryEventsPluginLibrary)];
public MemorySavestatePluginLibrary MemStateLib => (MemorySavestatePluginLibrary)Libraries[typeof(MemorySavestatePluginLibrary)];
public MoviePluginLibrary MovieLib => (MoviePluginLibrary)Libraries[typeof(MoviePluginLibrary)];
public SQLPluginLibrary SQLLib => (SQLPluginLibrary)Libraries[typeof(SQLPluginLibrary)];
public UserDataPluginLibrary UserDataLib => (UserDataPluginLibrary)Libraries[typeof(UserDataPluginLibrary)];
public Dictionary<Type, PluginLibraryBase> Libraries { get; set; }
public PluginAPI(Dictionary<Type, PluginLibraryBase> libs)
{
Libraries = libs;
}
}
}

View File

@ -6,7 +6,7 @@ using System.Reflection;
using System.Windows.Forms;
using BizHawk.Emulation.Common;
using BizHawk.Client.Common;
using BizHawk.Client.ApiHawk;
namespace BizHawk.Client.EmuHawk
{
@ -66,6 +66,8 @@ namespace BizHawk.Client.EmuHawk
continue;
if (!ServiceInjector.IsAvailable(Emulator.ServiceProvider, t))
continue;
// if (!ApiInjector.IsAvailable(, t))
// continue;
var instance = Activator.CreateInstance(t);

View File

@ -7,6 +7,7 @@ using System.Reflection;
using System.ComponentModel;
using System.Windows.Forms;
using BizHawk.Client.ApiHawk;
using BizHawk.Client.Common;
using BizHawk.Emulation.Common;
using BizHawk.Common.ReflectionExtensions;
@ -121,6 +122,11 @@ namespace BizHawk.Client.EmuHawk
(newTool as Form).Owner = GlobalWin.MainForm;
}
if (isExternal)
{
ApiInjector.UpdateApis(GlobalWin.ApiProvider, newTool);
}
ServiceInjector.UpdateServices(Global.Emulator.ServiceProvider, newTool);
string toolType = typeof(T).ToString();
@ -491,6 +497,8 @@ namespace BizHawk.Client.EmuHawk
if ((tool.IsHandleCreated && !tool.IsDisposed) || tool is RamWatch) // Hack for RAM Watch - in display watches mode it wants to keep running even closed, it will handle disposed logic
{
if (tool is IExternalToolForm)
ApiInjector.UpdateApis(GlobalWin.ApiProvider, tool);
tool.Restart();
}
}

View File

@ -109,4 +109,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>