Add Save/Load state methods and events to ApiHawk

Now, ApiHawk can save and load name state. There are also events that
you can attached too. Furthermore, BeforeQuickSave/BeforeQuickLoad
events occurs just after user pressed button. We can react to this and
even override behavior.
Finally, I just allow .bat to take xml files (for ApiHawk doc)

PS: Yeah, I'm still alive
This commit is contained in:
Hathor86 2016-05-29 16:50:16 +02:00
parent 3ef327e748
commit 7fb0eaf337
14 changed files with 460 additions and 8 deletions

View File

@ -99,6 +99,14 @@
<Compile Include="Attributes\BizHawkExternalToolUsageAttribute.cs" />
<Compile Include="Attributes\BizHawkExternalToolAttribute.cs" />
<Compile Include="Classes\BizHawkSystemIdToCoreSystemEnumConverter.cs" />
<Compile Include="Classes\Events\EventArgs\BeforeQuickLoadEventArgs.cs" />
<Compile Include="Classes\Events\EventArgs\BeforeQuickSaveEventArgs.cs" />
<Compile Include="Classes\Events\EventArgs\StateSavedEventArgs.cs" />
<Compile Include="Classes\Events\EventArgs\StateLoadedEventArgs.cs" />
<Compile Include="Classes\Events\EventHandlers\BeforeQuickLoadEventhandler.cs" />
<Compile Include="Classes\Events\EventHandlers\BeforeQuickSaveEventhandler.cs" />
<Compile Include="Classes\Events\EventHandlers\StateLoadedEventHandler.cs" />
<Compile Include="Classes\Events\EventHandlers\StateSavedEventHandler.cs" />
<Compile Include="Classes\Joypad.cs" />
<Compile Include="Classes\JoypadStringToEnumConverter.cs" />
<Compile Include="Enums\BizHawkExternalToolUsage.cs" />

View File

@ -4,11 +4,12 @@ using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Emulation.Cores.PCEngine;
using BizHawk.Emulation.Cores.Sega.MasterSystem;
using BizHawk.Client.ApiHawk.Classes.Events;
using System.IO;
namespace BizHawk.Client.ApiHawk
{
@ -28,10 +29,31 @@ namespace BizHawk.Client.ApiHawk
internal static readonly BizHawkSystemIdToEnumConverter SystemIdConverter = new BizHawkSystemIdToEnumConverter();
internal static readonly JoypadStringToEnumConverter JoypadConverter = new JoypadStringToEnumConverter();
public static event EventHandler RomLoaded;
private static List<Joypad> allJoypads;
/// <summary>
/// Occurs before a quickload is done (just after user has pressed the shortcut button
/// or has click on the item menu)
/// </summary>
public static event BeforeQuickLoadEventHandler BeforeQuickLoad;
/// <summary>
/// Occurs before a quicksave is done (just after user has pressed the shortcut button
/// or has click on the item menu)
/// </summary>
public static event BeforeQuickSaveEventHandler BeforeQuickSave;
/// <summary>
/// Occurs when a ROM is succesfully loaded
/// </summary>
public static event EventHandler RomLoaded;
/// <summary>
/// Occurs when a savestate is sucessfully loaded
/// </summary>
public static event StateLoadedEventHandler StateLoaded;
/// <summary>
/// Occurs when a savestate is successfully saved
/// </summary>
public static event StateSavedEventHandler StateSaved;
#endregion
#region cTor(s)
@ -95,6 +117,80 @@ namespace BizHawk.Client.ApiHawk
}
}
/// <summary>
/// Load a savestate specified by its name
/// </summary>
/// <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 });
}
/// <summary>
/// Raised before a quickload is done (just after pressing shortcut button)
/// </summary>
/// <param name="sender">Object who raised the event</param>
/// <param name="quickSaveSlotName">Slot used for quickload</param>
/// <param name="eventHandled">A boolean that can be set if users want to handle save themselves; if so, BizHawk won't do anything</param>
public static void OnBeforeQuickLoad(object sender, string quickSaveSlotName, out bool eventHandled)
{
eventHandled = false;
if (BeforeQuickLoad != null)
{
BeforeQuickLoadEventArgs e = new BeforeQuickLoadEventArgs(quickSaveSlotName);
BeforeQuickLoad(sender, e);
eventHandled = e.Handled;
}
}
/// <summary>
/// Raised before a quicksave is done (just after pressing shortcut button)
/// </summary>
/// <param name="sender">Object who raised the event</param>
/// <param name="quickSaveSlotName">Slot used for quicksave</param>
/// <param name="eventHandled">A boolean that can be set if users want to handle save themselves; if so, BizHawk won't do anything</param>
public static void OnBeforeQuickSave(object sender, string quickSaveSlotName, out bool eventHandled)
{
eventHandled = false;
if (BeforeQuickSave != null)
{
BeforeQuickSaveEventArgs e = new BeforeQuickSaveEventArgs(quickSaveSlotName);
BeforeQuickSave(sender, e);
eventHandled = e.Handled;
}
}
/// <summary>
/// Raise when a state is loaded
/// </summary>
/// <param name="sender">Object who raised the event</param>
/// <param name="stateName">User friendly name for saved state</param>
public static void OnStateLoaded(object sender, string stateName)
{
if (StateLoaded != null)
{
StateLoaded(sender, new StateLoadedEventArgs(stateName));
}
}
/// <summary>
/// Raise when a state is saved
/// </summary>
/// <param name="sender">Object who raised the event</param>
/// <param name="stateName">User friendly name for saved state</param>
public static void OnStateSaved(object sender, string stateName)
{
if (StateSaved != null)
{
StateSaved(sender, new StateSavedEventArgs(stateName));
}
}
/// <summary>
/// Raise when a rom is successfully Loaded
/// </summary>
@ -113,6 +209,17 @@ namespace BizHawk.Client.ApiHawk
}
/// <summary>
/// Save a state with specified name
/// </summary>
/// <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 });
}
/// <summary>
/// Sets the extra padding added to the 'native' surface so that you can draw HUD elements in predictable placements
/// </summary>

View File

@ -0,0 +1,68 @@
using System;
namespace BizHawk.Client.ApiHawk.Classes.Events
{
/// <summary>
/// This class holds event data for BeforeQuickLoad event
/// </summary>
public sealed class BeforeQuickLoadEventArgs : EventArgs
{
#region Fields
private bool _Handled = false;
private string _QuickSaveSlotName;
#endregion
#region cTor(s)
internal BeforeQuickLoadEventArgs(string name)
{
_QuickSaveSlotName = name;
}
#endregion
#region Properties
/// <summary>
/// Gets or sets value that defined if saved has been handled or not
/// </summary>
public bool Handled
{
get
{
return _Handled;
}
set
{
_Handled = value;
}
}
/// <summary>
/// Gets quicksave name
/// </summary>
public string Name
{
get
{
return _QuickSaveSlotName;
}
}
/// <summary>
/// Gets slot used for quicksave
/// </summary>
public int Slot
{
get
{
return int.Parse(_QuickSaveSlotName.Substring(_QuickSaveSlotName.Length - 1));
}
}
#endregion
}
}

View File

@ -0,0 +1,69 @@
using System;
namespace BizHawk.Client.ApiHawk.Classes.Events
{
/// <summary>
/// This class holds event data for BeforeQuickSave event
/// </summary>
public sealed class BeforeQuickSaveEventArgs : EventArgs
{
#region Fields
private bool _Handled = false;
private string _QuickSaveSlotName;
#endregion
#region cTor(s)
internal BeforeQuickSaveEventArgs(string name)
{
_QuickSaveSlotName = name;
}
#endregion
#region Properties
/// <summary>
/// Gets or sets value that defined if saved has been handled or not
/// </summary>
public bool Handled
{
get
{
return _Handled;
}
set
{
_Handled = value;
}
}
/// <summary>
/// Gets quicksave name
/// </summary>
public string Name
{
get
{
return _QuickSaveSlotName;
}
}
/// <summary>
/// Gets slot used for quicksave
/// </summary>
public int Slot
{
get
{
return int.Parse(_QuickSaveSlotName.Substring(_QuickSaveSlotName.Length - 1));
}
}
#endregion
}
}

View File

@ -0,0 +1,44 @@
using System;
namespace BizHawk.Client.ApiHawk.Classes.Events
{
/// <summary>
/// This class holds event data for StateLoaded event
/// </summary>
public sealed class StateLoadedEventArgs: EventArgs
{
#region Fields
string _Name;
#endregion
#region cTor(s)
/// <summary>
/// Initialize a new instance of <see cref="StateLoadedEventArgs"/>
/// </summary>
/// <param name="stateName">User friendly name of loaded state</param>
internal StateLoadedEventArgs(string stateName)
{
_Name = stateName;
}
#endregion
#region Properties
/// <summary>
/// Gets user friendly name of the loaded savestate
/// </summary>
public string Name
{
get
{
return _Name;
}
}
#endregion
}
}

View File

@ -0,0 +1,44 @@
using System;
namespace BizHawk.Client.ApiHawk.Classes.Events
{
/// <summary>
/// This class holds event data for StateSaved event
/// </summary>
public sealed class StateSavedEventArgs : EventArgs
{
#region Fields
string _Name;
#endregion
#region cTor(s)
/// <summary>
/// Initialize a new instance of <see cref="StateSavedEventArgs"/>
/// </summary>
/// <param name="stateName">User friendly name of loaded state</param>
internal StateSavedEventArgs(string stateName)
{
_Name = stateName;
}
#endregion
#region Properties
/// <summary>
/// Gets user friendly name of the loaded savestate
/// </summary>
public string Name
{
get
{
return _Name;
}
}
#endregion
}
}

View File

@ -0,0 +1,9 @@
namespace BizHawk.Client.ApiHawk.Classes.Events
{
/// <summary>
/// Represent a method that will handle the event raised before a quickload is done
/// </summary>
/// <param name="sender">Object that raised the event</param>
/// <param name="e">Event arguments</param>
public delegate void BeforeQuickLoadEventHandler(object sender, BeforeQuickLoadEventArgs e);
}

View File

@ -0,0 +1,9 @@
namespace BizHawk.Client.ApiHawk.Classes.Events
{
/// <summary>
/// Represent a method that will handle the event raised before a quicksave is done
/// </summary>
/// <param name="sender">Object that raised the event</param>
/// <param name="e">Event arguments</param>
public delegate void BeforeQuickSaveEventHandler(object sender, BeforeQuickSaveEventArgs e);
}

View File

@ -0,0 +1,9 @@
namespace BizHawk.Client.ApiHawk.Classes.Events
{
/// <summary>
/// Represent a method that will handle the event raised when a savestate is loaded
/// </summary>
/// <param name="sender">Object that raised the event</param>
/// <param name="e">Event arguments</param>
public delegate void StateLoadedEventHandler(object sender, StateLoadedEventArgs e);
}

View File

@ -0,0 +1,9 @@
namespace BizHawk.Client.ApiHawk.Classes.Events
{
/// <summary>
/// Represent a method that will handle the event raised when a savestate is saved
/// </summary>
/// <param name="sender">Object that raised the event</param>
/// <param name="e">Event arguments</param>
public delegate void StateSavedEventHandler(object sender, StateSavedEventArgs e);
}

View File

@ -75,12 +75,13 @@ namespace BizHawk.Client.ApiHawk
/// </summary>
/// <param name="fileName">File that will be reflected</param>
/// <returns>A new <see cref="ToolStripMenuItem"/>; assembly path can be found in the Tag property</returns>
/// <remarks>For the moment, you could only load a dll that have a form (which implements <see cref="IExternalToolForm"/>)</remarks>
/// <remarks>For the moment, you could only load a dll that have a form (which implements <see cref="BizHawk.Client.EmuHawk.IExternalToolForm"/>)</remarks>
private static ToolStripMenuItem GenerateToolTipFromFileName(string fileName)
{
Type customFormType;
Assembly externalToolFile;
ToolStripMenuItem item = null;
try
{
externalToolFile = Assembly.LoadFrom(fileName);

View File

@ -53,7 +53,7 @@
<Class Name="BizHawk.Client.ApiHawk.ClientApi">
<Position X="4.75" Y="10" Width="4" />
<TypeIdentifier>
<HashCode>CQEAAAAAgAAAQAAAAAABQAIAAAAAoGAACCAAAAAQAAA=</HashCode>
<HashCode>CwEAAAAAgAMAQEAAAAAJQAoAAAEAgWAACCACAAAQAiA=</HashCode>
<FileName>Classes\ClientApi.cs</FileName>
</TypeIdentifier>
</Class>
@ -81,14 +81,42 @@
<Class Name="BizHawk.Client.ApiHawk.Joypad">
<Position X="0.75" Y="6.75" Width="3" />
<TypeIdentifier>
<HashCode>AQAACAAAAIAAAACBAAgAAABAEAAAAAAAAAAAAAAAAAA=</HashCode>
<HashCode>AQAACAAAAIAAAACBAAgAAABAEAAAAAAAAAACGAAAAAA=</HashCode>
<FileName>Classes\Joypad.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="BizHawk.Client.Common.SystemInfo">
<Position X="0.5" Y="10.25" Width="4" />
<Position X="0.5" Y="11" Width="4" />
<TypeIdentifier />
</Class>
<Class Name="BizHawk.Client.ApiHawk.Classes.Events.StateLoadedEventArgs">
<Position X="41.75" Y="2.25" Width="3" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAIAQAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Classes\Events\EventArgs\StateLoadedEventArgs.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="BizHawk.Client.ApiHawk.Classes.Events.StateSavedEventArgs">
<Position X="38.25" Y="2.25" Width="3" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAIAQAAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Classes\Events\EventArgs\StateSavedEventArgs.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="BizHawk.Client.ApiHawk.Classes.Events.BeforeQuickSaveEventArgs">
<Position X="38.25" Y="6.75" Width="3" />
<TypeIdentifier>
<HashCode>AAAAAAAAIAAAQAAAAACAAAAAAAAAAAAAAAAAAAAAAgA=</HashCode>
<FileName>Classes\Events\EventArgs\BeforeQuickSaveEventArgs.cs</FileName>
</TypeIdentifier>
</Class>
<Class Name="BizHawk.Client.ApiHawk.Classes.Events.BeforeQuickLoadEventArgs">
<Position X="41.75" Y="6.75" Width="3" />
<TypeIdentifier>
<HashCode>AAAAAAAAIAAAQAAAAACAAAAAAAAAAAAAAAAAAAAAAgA=</HashCode>
<FileName>Classes\Events\EventArgs\BeforeQuickLoadEventArgs.cs</FileName>
</TypeIdentifier>
</Class>
<Interface Name="BizHawk.Client.EmuHawk.IExternalToolForm">
<Position X="4.5" Y="4.5" Width="2.75" />
<TypeIdentifier>
@ -131,5 +159,33 @@
<Position X="28.25" Y="9.75" Width="1.5" />
<TypeIdentifier />
</Enum>
<Delegate Name="BizHawk.Client.ApiHawk.Classes.Events.StateLoadedEventHandler">
<Position X="41.75" Y="1" Width="2" />
<TypeIdentifier>
<HashCode>AAAAAAAQAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAA=</HashCode>
<FileName>Classes\Events\EventHandlers\StateLoadedEventHandler.cs</FileName>
</TypeIdentifier>
</Delegate>
<Delegate Name="BizHawk.Client.ApiHawk.Classes.Events.StateSavedEventHandler">
<Position X="38.25" Y="1" Width="2" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAgA=</HashCode>
<FileName>Classes\Events\EventHandlers\StateSavedEventHandler.cs</FileName>
</TypeIdentifier>
</Delegate>
<Delegate Name="BizHawk.Client.ApiHawk.Classes.Events.BeforeQuickSaveEventHandler">
<Position X="38.25" Y="5.5" Width="2.25" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAEA=</HashCode>
<FileName>Classes\Events\EventHandlers\BeforeQuickSaveEventhandler.cs</FileName>
</TypeIdentifier>
</Delegate>
<Delegate Name="BizHawk.Client.ApiHawk.Classes.Events.BeforeQuickLoadEventHandler">
<Position X="41.75" Y="5.5" Width="2.25" />
<TypeIdentifier>
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAACAAAAA=</HashCode>
<FileName>Classes\Events\EventHandlers\BeforeQuickLoadEventhandler.cs</FileName>
</TypeIdentifier>
</Delegate>
<Font Name="Segoe UI" Size="9" />
</ClassDiagram>

View File

@ -34,6 +34,7 @@ using BizHawk.Emulation.Cores.Nintendo.N64;
using BizHawk.Client.EmuHawk.WinFormExtensions;
using BizHawk.Client.EmuHawk.ToolExtensions;
using BizHawk.Client.EmuHawk.CoreExtensions;
using BizHawk.Client.ApiHawk;
namespace BizHawk.Client.EmuHawk
{
@ -3700,6 +3701,8 @@ namespace BizHawk.Client.EmuHawk
if (SavestateManager.LoadStateFile(path, userFriendlyStateName))
{
ClientApi.OnStateLoaded(this, userFriendlyStateName);
if (GlobalWin.Tools.Has<LuaConsole>())
{
GlobalWin.Tools.LuaConsole.LuaImp.CallLoadStateEvent(userFriendlyStateName);
@ -3732,6 +3735,13 @@ namespace BizHawk.Client.EmuHawk
return;
}
bool handled;
ClientApi.OnBeforeQuickLoad(this, quickSlotName, out handled);
if (handled)
{
return;
}
if (IsSlave && master.WantsToControlSavestates)
{
master.LoadQuickSave(SlotToInt(quickSlotName));
@ -3766,6 +3776,8 @@ namespace BizHawk.Client.EmuHawk
{
SavestateManager.SaveStateFile(path, userFriendlyStateName);
ClientApi.OnStateSaved(this, userFriendlyStateName);
GlobalWin.OSD.AddMessage("Saved state: " + userFriendlyStateName);
}
catch (IOException)
@ -3786,6 +3798,13 @@ namespace BizHawk.Client.EmuHawk
return;
}
bool handled;
ClientApi.OnBeforeQuickSave(this, quickSlotName, out handled);
if(handled)
{
return;
}
if (IsSlave && master.WantsToControlSavestates)
{
master.SaveQuickSave(SlotToInt(quickSlotName));

View File

@ -33,7 +33,7 @@ rem explicitly list the OK ones here as individual copies. until then....
copy *.dll dll
rem Now, we're about to zip and then unzip. Why, you ask? Because that's just the way this evolved.
..\dist\zip.exe -X -r ..\Dist\%NAME% EmuHawk.exe DiscoHawk.exe defctrl.json dll shaders gamedb Tools NES\Palettes Lua Gameboy\Palettes -x *.pdb -x *.lib -x *.pgd -x *.ipdb -x *.iobj -x *.exp -x dll\libsneshawk-64*.exe -x *.ilk -x dll\gpgx.elf -x dll\miniclient.* -x dll\*.xml
..\dist\zip.exe -X -r ..\Dist\%NAME% EmuHawk.exe DiscoHawk.exe defctrl.json dll shaders gamedb Tools NES\Palettes Lua Gameboy\Palettes -x *.pdb -x *.lib -x *.pgd -x *.ipdb -x *.iobj -x *.exp -x dll\libsneshawk-64*.exe -x *.ilk -x dll\gpgx.elf -x dll\miniclient.*
cd ..\Dist
.\unzip.exe %NAME% -d temp