- IToolForm: Added RequiredServices attribute to define dependencies, and added EmulatorServices for ToolManager to supply them.

- IServiceProvider, BasicServiceProvider: Added compile-time unknown type versions of GetService and HasService.
- ToolManager: Added IsAvailable to test whether all dependencies for a tool are available.
This commit is contained in:
scepheo 2014-12-13 21:54:59 +00:00
parent c6ed49c067
commit 769cbeb1a0
34 changed files with 164 additions and 11 deletions

View File

@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Emulation.Cores.Nintendo.NES;
@ -11,6 +11,8 @@ namespace BizHawk.Client.EmuHawk
private NES.NESSettings _oldSettings;
private NES.NESSettings _settings;
public IDictionary<Type, object> EmulatorServices { private get; set; }
public bool AskSaveChanges() { return true; }
public bool UpdateBefore { get { return false; } }
public void UpdateValues()

View File

@ -25,6 +25,8 @@ namespace BizHawk.Client.EmuHawk
// Video Frame advance
// Add to toolbox
public IDictionary<Type, object> EmulatorServices { private get; set; }
private Atari2600 _core = Global.Emulator as Atari2600;
private readonly List<string> _instructions = new List<string>();

View File

@ -19,6 +19,8 @@ namespace BizHawk.Client.EmuHawk
{
public partial class Cheats : Form, IToolForm
{
public IDictionary<Type, object> EmulatorServices { private get; set; }
public const string NAME = "NamesColumn";
public const string ADDRESS = "AddressColumn";
public const string VALUE = "ValueColumn";

View File

@ -21,6 +21,8 @@ namespace BizHawk.Client.EmuHawk
private IDebuggable Core;
private IDisassemblable Disassembler;
public IDictionary<Type, object> EmulatorServices { private get; set; }
public GenericDebugger()
{
InitializeComponent();

View File

@ -7,11 +7,14 @@ using BizHawk.Common.NumberExtensions;
using BizHawk.Client.Common;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Client.EmuHawk.WinFormExtensions;
using System.Collections.Generic;
namespace BizHawk.Client.EmuHawk
{
public partial class GBGPUView : Form, IToolForm
{
public IDictionary<Type, object> EmulatorServices { private get; set; }
// TODO: freeze semantics are a bit weird: details for a mouseover or freeze are taken from the current
// state, not the state at the last callback (and so can be quite different when update is set to manual).
// I'm not quite sure what's the best thing to do...

View File

@ -15,6 +15,8 @@ namespace BizHawk.Client.EmuHawk
private readonly Dictionary<char, int> _gameGenieTable = new Dictionary<char, int>();
private bool _processing;
public IDictionary<Type, object> EmulatorServices { private get; set; }
#region Public
public bool AskSaveChanges() { return true; }

View File

@ -6,6 +6,7 @@ using BizHawk.Common.NumberExtensions;
using BizHawk.Client.Common;
using BizHawk.Emulation.Cores.Nintendo.Gameboy;
using BizHawk.Emulation.Cores.Nintendo.GBA;
using System.Collections.Generic;
namespace BizHawk.Client.EmuHawk
{
@ -13,6 +14,8 @@ namespace BizHawk.Client.EmuHawk
{
IGBAGPUViewable gba;
public IDictionary<Type, object> EmulatorServices { private get; set; }
// emulator memory areas
private IntPtr vram;
private IntPtr oam;

View File

@ -50,6 +50,8 @@ namespace BizHawk.Client.EmuHawk
{ '9', 31 }
};
public IDictionary<Type, object> EmulatorServices { private get; set; }
private bool _processing;
private void GenGameGenie_Load(object sender, EventArgs e)

View File

@ -18,6 +18,8 @@ namespace BizHawk.Client.EmuHawk
private GPGX Emu;
int palindex = 0;
public IDictionary<Type, object> EmulatorServices { private get; set; }
public GenVDPViewer()
{
InitializeComponent();

View File

@ -22,6 +22,8 @@ namespace BizHawk.Client.EmuHawk
{
public partial class HexEditor : Form, IToolForm
{
public IDictionary<Type, object> EmulatorServices { private get; set; }
private bool fontSizeSet = false;
private int fontWidth;
private int fontHeight;

View File

@ -1,7 +1,18 @@
namespace BizHawk.Client.EmuHawk
using System;
using System.Linq;
using System.Collections.Generic;
namespace BizHawk.Client.EmuHawk
{
public interface IToolForm
{
/// <summary>
/// This should be used to approach any services required of the emulator
/// core. It will be populated by ToolManager with the services specified
/// in the tool's RequiredServices attribute.
/// </summary>
IDictionary<Type, object> EmulatorServices { set; }
/// <summary>
/// Will be called by the client anytime an Update needs to occur, such as after an emulated frame, a loadstate, or a related dialog has made a relevant change
/// </summary>
@ -28,7 +39,6 @@
/// <returns></returns>
bool AskSaveChanges();
/// <summary>
/// Indicates whether the tool should be updated before a frame loop or after.
/// In general, tools that draw graphics from the core should update before the loop,
@ -42,4 +52,19 @@
void Close();
bool IsDisposed { get; }
}
/// <summary>
/// Attribute used for IToolForms to indicate which IEmulatorServices they
/// need.
/// </summary>
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = true)]
sealed class RequiredServices : Attribute
{
public readonly Type[] Dependencies;
public RequiredServices(params Type[] requiredServices)
{
this.Dependencies = requiredServices;
}
}
}

View File

@ -19,6 +19,8 @@ namespace BizHawk.Client.EmuHawk
{
public partial class LuaConsole : Form, IToolForm
{
public IDictionary<Type, object> EmulatorServices { private get; set; }
private readonly LuaFileList _luaList;
private int _defaultWidth;
private int _defaultHeight;

View File

@ -16,6 +16,8 @@ namespace BizHawk.Client.EmuHawk
{
private DatachBarcode reader;
public IDictionary<Type, object> EmulatorServices { private get; set; }
public BarcodeEntry()
{
InitializeComponent();

View File

@ -10,6 +10,8 @@ namespace BizHawk.Client.EmuHawk
{
public partial class NESDebugger : Form, IToolForm
{
public IDictionary<Type, object> EmulatorServices { private get; set; }
private const int ADDR_MAX = 0xFFFF;
private const int DISASM_LINE_COUNT = 100;
private int defaultWidth; //For saving the default size of the dialog, so the user can restore if desired

View File

@ -11,6 +11,8 @@ namespace BizHawk.Client.EmuHawk
{
public partial class NESGameGenie : Form, IToolForm
{
public IDictionary<Type, object> EmulatorServices { private get; set; }
private readonly Dictionary<char, int> _gameGenieTable = new Dictionary<char, int>
{
{ 'A', 0 }, // 0000

View File

@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Emulation.Cores.Nintendo.NES;
@ -15,6 +15,8 @@ namespace BizHawk.Client.EmuHawk
private readonly NES.PPU.DebugCallback _callback = new NES.PPU.DebugCallback();
private NES _nes;
public IDictionary<Type, object> EmulatorServices { private get; set; }
public NESNameTableViewer()
{
InitializeComponent();

View File

@ -6,6 +6,7 @@ using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Emulation.Cores.Nintendo.NES;
using BizHawk.Emulation.Common;
using System.Collections.Generic;
namespace BizHawk.Client.EmuHawk
{
@ -26,6 +27,8 @@ namespace BizHawk.Client.EmuHawk
private NES _nes;
private bool _forceChange;
public IDictionary<Type, object> EmulatorServices { private get; set; }
public NesPPU()
{
InitializeComponent();

View File

@ -1,8 +1,8 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Emulation.Cores.PCEngine;
@ -13,6 +13,8 @@ namespace BizHawk.Client.EmuHawk
private PCEngine _pce;
private int _vdcType;
public IDictionary<Type, object> EmulatorServices { private get; set; }
public PceBgViewer()
{
InitializeComponent();

View File

@ -24,6 +24,8 @@ namespace BizHawk.Client.EmuHawk
private int _defaultWidth;
private int _defaultHeight;
public IDictionary<Type, object> EmulatorServices { private get; set; }
public PCECDL()
{
InitializeComponent();

View File

@ -20,6 +20,8 @@ namespace BizHawk.Client.EmuHawk
{
public partial class PCESoundDebugger : Form, IToolForm
{
public IDictionary<Type, object> EmulatorServices { private get; set; }
public PCESoundDebugger()
{
InitializeComponent();

View File

@ -22,6 +22,8 @@ namespace BizHawk.Client.EmuHawk
private int bgpalnum;
private int sppalnum;
public IDictionary<Type, object> EmulatorServices { private get; set; }
public PCETileViewer()
{
InitializeComponent();

View File

@ -18,6 +18,8 @@ namespace BizHawk.Client.EmuHawk
private VDP vdp;
int palindex = 0;
public IDictionary<Type, object> EmulatorServices { private get; set; }
public SmsVDPViewer()
{
InitializeComponent();

View File

@ -38,6 +38,8 @@ namespace BizHawk.Client.EmuHawk
private bool _processing;
public IDictionary<Type, object> EmulatorServices { private get; set; }
public SNESGameGenie()
{
InitializeComponent();

View File

@ -46,6 +46,8 @@ namespace BizHawk.Client.EmuHawk
public bool UpdateBefore { get { return false; } }
public bool AskSaveChanges() { return true; }
public IDictionary<Type, object> EmulatorServices { private get; set; }
public void Restart()
{
if (Global.Emulator is LibsnesCore)

View File

@ -1,7 +1,11 @@
namespace BizHawk.Client.EmuHawk
using System;
using System.Collections.Generic;
namespace BizHawk.Client.EmuHawk
{
public partial class TAStudio : IControlMainform
{
public IDictionary<Type, object> EmulatorServices { private get; set; }
private bool _suppressAskSave = false;
public bool WantsToControlReadOnly { get { return false; } }

View File

@ -1,6 +1,6 @@
using System;
using System.Collections.Generic;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Emulation.Cores.Calculators;
@ -8,6 +8,8 @@ namespace BizHawk.Client.EmuHawk
{
public partial class TI83KeyPad : Form, IToolForm
{
public IDictionary<Type, object> EmulatorServices { private get; set; }
public TI83KeyPad()
{
InitializeComponent();

View File

@ -19,6 +19,8 @@ namespace BizHawk.Client.EmuHawk
{
public partial class ToolBox : Form, IToolForm
{
public IDictionary<Type, object> EmulatorServices { private get; set; }
public ToolBox()
{
InitializeComponent();

View File

@ -40,6 +40,35 @@ namespace BizHawk.Client.EmuHawk
return result;
}
/// <summary>
/// Gets all the IEmulatorServices the tool needs, as defined in its
/// RequiredServices attribute. If no attribute is defined, returns an
/// empty array.
/// </summary>
public Type[] GetDependencies<T>()
where T : IToolForm
{
var attribute = (RequiredServices)typeof(T)
.GetCustomAttributes(typeof(RequiredServices), false)
.FirstOrDefault();
if (attribute == null)
return new Type[0];
else
return attribute.Dependencies;
}
/// <summary>
/// Determines whether a tool is available, considering its dependencies
/// and the services provided by the emulator core.
/// </summary>
public bool IsAvailable<T>()
where T : IToolForm
{
return GetDependencies<T>()
.All(t => Global.Emulator.ServiceProvider.HasService(typeof(T)));
}
/// <summary>
/// Determines whether a given IToolForm is already loaded
/// </summary>

View File

@ -26,6 +26,8 @@ namespace BizHawk.Client.EmuHawk
private int _defaultWidth;
private int _defaultHeight;
public IDictionary<Type, object> EmulatorServices { private get; set; }
public TraceLogger()
{
InitializeComponent();

View File

@ -25,6 +25,7 @@ namespace BizHawk.Client.EmuHawk
}
}
public IDictionary<Type, object> EmulatorServices { private get; set; }
public bool Readonly
{

View File

@ -55,6 +55,8 @@ namespace BizHawk.Client.EmuHawk
public const int MaxDetailedSize = 1024 * 1024; // 1mb, semi-arbituary decision, sets the size to check for and automatically switch to fast mode for the user
public const int MaxSupportedSize = 1024 * 1024 * 64; // 64mb, semi-arbituary decision, sets the maximum size ram search will support (as it will crash beyond this)
public IDictionary<Type, object> EmulatorServices { private get; set; }
public bool AskSaveChanges()
{
return true;

View File

@ -39,6 +39,8 @@ namespace BizHawk.Client.EmuHawk
private bool _sortReverse;
private bool _paused = false;
public IDictionary<Type, object> EmulatorServices { private get; set; }
public RamWatch()
{
_core = (IMemoryDomains)Global.Emulator; // Cast is intentional, better to get a cast exception than a null reference exception later

View File

@ -70,17 +70,40 @@ namespace BizHawk.Emulation.Common
}
}
public IEmulatorService GetService(Type t)
{
if (typeof(IEmulatorService).IsAssignableFrom(t))
{
IEmulatorService service;
if (Services.TryGetValue(t, out service))
return service;
else
return null;
}
else
{
throw new Exception(String.Format("Type {0} does not implement IEmulatorService.", t.Name));
}
}
public bool HasService<T>()
where T : IEmulatorService
{
IEmulatorService service;
if (Services.TryGetValue(typeof(T), out service))
return Services.TryGetValue(typeof(T), out service);
}
public bool HasService(Type t)
{
if (typeof(IEmulatorService).IsAssignableFrom(t))
{
return true;
IEmulatorService service;
return Services.TryGetValue(t, out service);
}
else
{
return false;
throw new Exception(String.Format("Type {0} does not implement IEmulatorService.", t.Name));
}
}
}

View File

@ -1,4 +1,5 @@
namespace BizHawk.Emulation.Common
using System;
namespace BizHawk.Emulation.Common
{
public interface IEmulatorServiceProvider
{
@ -6,11 +7,22 @@
/// Returns whether or not T is available
/// </summary>
bool HasService<T>() where T : IEmulatorService;
/// <summary>
/// Returns whether or not t is available
/// </summary>
bool HasService(Type t);
/// <summary>
/// Returns an instance of T if T is available
/// Else returns null
/// </summary>
IEmulatorService GetService<T>() where T : IEmulatorService;
/// <summary>
/// Returns an instance of t if t is available
/// Else returns null
/// </summary>
IEmulatorService GetService(Type t);
}
}