BizHawk/BizHawk.Client.EmuHawk/CoreFeatureAnalysis.cs

301 lines
7.5 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System.Reflection;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Common.IEmulatorExtensions;
using BizHawk.Client.Common;
namespace BizHawk.Client.EmuHawk
{
public partial class CoreFeatureAnalysis : Form, IToolFormAutoConfig
{
#region ConfigPersist
private class CoreInfo
{
public string CoreName { get; set; }
public string TypeName { get; set; }
public bool Released { get; set; }
public Dictionary<string, ServiceInfo> Services { get; set; }
public List<string> NotApplicableTypes { get; set; }
public CoreInfo() { }
public CoreInfo(IEmulator emu)
{
TypeName = emu.GetType().ToString();
CoreName = emu.Attributes().CoreName;
Released = emu.Attributes().Released;
Services = new Dictionary<string, ServiceInfo>();
var ser = emu.ServiceProvider;
foreach (Type t in ser.AvailableServices.Where(type => type != emu.GetType()))
{
var si = new ServiceInfo(t, ser.GetService(t));
Services.Add(si.TypeName, si);
}
var notapplicableAttr = ((ServiceNotApplicable)Attribute
.GetCustomAttribute(emu.GetType(), typeof(ServiceNotApplicable)));
if (notapplicableAttr != null)
{
NotApplicableTypes = notapplicableAttr.NotApplicableTypes
.Select(x => x.ToString())
.ToList();
}
else
{
NotApplicableTypes = new List<string>();
}
}
}
private class ServiceInfo
{
public string TypeName { get; set; }
public bool Complete { get; set; }
public List<FunctionInfo> Functions { get; set; }
public ServiceInfo() { }
public ServiceInfo(Type servicetype, object service)
{
if (servicetype.IsGenericType)
{
TypeName = servicetype.GetGenericTypeDefinition().ToString();
}
else
{
TypeName = servicetype.ToString();
}
Functions = new List<FunctionInfo>();
IEnumerable<MethodInfo> methods = servicetype.GetMethods(); // .Concat(servicetype.GetProperties().Select(p => p.GetGetMethod()));
if (servicetype.IsInterface)
{
var map = service.GetType().GetInterfaceMap(servicetype);
// project interface methods to actual implementations
methods = methods.Select(
m => map.TargetMethods[Array.IndexOf(map.InterfaceMethods, m)]);
}
foreach (var method in methods)
{
Functions.Add(new FunctionInfo(method, service));
}
Complete = Functions.All(f => f.Complete);
}
}
private class FunctionInfo
{
public string TypeName { get; set; }
public bool Complete { get; set; }
public FunctionInfo() { }
public FunctionInfo(MethodInfo m, object service)
{
TypeName = m.ToString();
try
{
Complete = m.IsImplemented();
}
catch
{
Complete = false; // TODO: fixme
}
}
}
[ConfigPersist]
private Dictionary<string, CoreInfo> KnownCores { get; set; }
#endregion
[RequiredService]
IEmulator emu { get; set; }
public CoreFeatureAnalysis()
{
InitializeComponent();
KnownCores = new Dictionary<string, CoreInfo>();
}
private void OkBtn_Click(object sender, EventArgs e)
{
Close();
}
private TreeNode CreateCoreTree(CoreInfo ci)
{
var ret = new TreeNode
{
Text = ci.CoreName + (ci.Released ? string.Empty : " (UNRELEASED)"),
ForeColor = ci.Released ? Color.Black : Color.DarkGray
};
foreach (var service in ci.Services.Values)
{
string img = service.Complete ? "Good" : "Bad";
var serviceNode = new TreeNode
{
Text = service.TypeName,
ForeColor = service.Complete ? Color.Black : Color.Red,
ImageKey = img,
SelectedImageKey = img,
StateImageKey = img
};
foreach (var function in service.Functions)
{
img = function.Complete ? "Good" : "Bad";
serviceNode.Nodes.Add(new TreeNode
{
Text = function.TypeName,
ForeColor = function.Complete ? Color.Black : Color.Red,
ImageKey = img,
SelectedImageKey = img,
StateImageKey = img
});
}
ret.Nodes.Add(serviceNode);
}
var knownServies = Assembly.GetAssembly(typeof(IEmulator))
.GetTypes()
.Where(t => typeof(IEmulatorService).IsAssignableFrom(t))
.Where(t => t != typeof(IEmulatorService))
.Where(t => t.IsInterface)
.Select(t => t.ToString());
var additionalServices = knownServies
.Where(s => !ci.Services.ContainsKey(s))
.Where(s => !ci.NotApplicableTypes.Contains(s));
foreach (string servicename in additionalServices)
{
string img = "Bad";
var serviceNode = new TreeNode
{
Text = servicename,
ForeColor = Color.Red,
ImageKey = img,
SelectedImageKey = img,
StateImageKey = img
};
ret.Nodes.Add(serviceNode);
}
return ret;
}
private void DoCurrentCoreTree(CoreInfo ci)
{
CurrentCoreTree.ImageList = new ImageList();
CurrentCoreTree.ImageList.Images.Add("Good", Properties.Resources.GreenCheck);
CurrentCoreTree.ImageList.Images.Add("Bad", Properties.Resources.ExclamationRed);
CurrentCoreTree.Nodes.Clear();
CurrentCoreTree.BeginUpdate();
var coreNode = CreateCoreTree(ci);
coreNode.Expand();
CurrentCoreTree.Nodes.Add(coreNode);
CurrentCoreTree.EndUpdate();
}
private void DoAllCoresTree(CoreInfo current_ci)
{
CoreTree.ImageList = new ImageList();
CoreTree.ImageList.Images.Add("Good", Properties.Resources.GreenCheck);
CoreTree.ImageList.Images.Add("Bad", Properties.Resources.ExclamationRed);
CoreTree.ImageList.Images.Add("Unknown", Properties.Resources.RetroQuestion);
var possiblecoretypes =
Assembly
.Load("BizHawk.Emulation.Cores")
.GetTypes()
.Where(t => typeof(IEmulator).IsAssignableFrom(t) && !t.IsAbstract)
.Select(t => new
{
Type = t,
CoreAttributes = (CoreAttributes)t.GetCustomAttributes(typeof(CoreAttributes), false).First()
})
.OrderByDescending(t => t.CoreAttributes.Released)
.ThenBy(t => t.CoreAttributes.CoreName)
.ToList();
toolStripStatusLabel1.Text = string.Format("Total: {0} Released: {1} Profiled: {2}",
possiblecoretypes.Count,
KnownCores.Values.Count(c => c.Released),
KnownCores.Count);
CoreTree.Nodes.Clear();
CoreTree.BeginUpdate();
foreach (var ci in KnownCores.Values)
{
var coreNode = CreateCoreTree(ci);
if (ci.CoreName == current_ci.CoreName)
{
coreNode.Expand();
}
CoreTree.Nodes.Add(coreNode);
}
foreach (var t in possiblecoretypes)
{
if (!KnownCores.ContainsKey(t.CoreAttributes.CoreName))
{
string img = "Unknown";
var coreNode = new TreeNode
{
Text = t.CoreAttributes.CoreName + (t.CoreAttributes.Released ? string.Empty : " (UNRELEASED)"),
ForeColor = t.CoreAttributes.Released ? Color.Black : Color.DarkGray,
ImageKey = img,
SelectedImageKey = img,
StateImageKey = img
};
CoreTree.Nodes.Add(coreNode);
}
}
CoreTree.EndUpdate();
}
#region IToolForm
public void UpdateValues()
{
}
public void FastUpdate()
{
}
public void Restart()
{
var ci = new CoreInfo(emu);
KnownCores[ci.CoreName] = ci;
DoCurrentCoreTree(ci);
DoAllCoresTree(ci);
}
public bool AskSaveChanges()
{
return true;
}
public bool UpdateBefore
{
get { return false; }
}
#endregion
}
}