From c5daf82a3b75593e71200ab4d917bd91200bd6f4 Mon Sep 17 00:00:00 2001 From: goyuken Date: Fri, 16 Jan 2015 00:48:40 +0000 Subject: [PATCH] some changes to corefeatureanalysis --- .../CoreFeatureAnalysis.Designer.cs | 42 +- BizHawk.Client.EmuHawk/CoreFeatureAnalysis.cs | 359 +++++++++--------- .../CoreFeatureAnalysis.resx | 3 + BizHawk.Client.EmuHawk/MainForm.cs | 2 +- 4 files changed, 218 insertions(+), 188 deletions(-) diff --git a/BizHawk.Client.EmuHawk/CoreFeatureAnalysis.Designer.cs b/BizHawk.Client.EmuHawk/CoreFeatureAnalysis.Designer.cs index b9ca90479a..601fa60844 100644 --- a/BizHawk.Client.EmuHawk/CoreFeatureAnalysis.Designer.cs +++ b/BizHawk.Client.EmuHawk/CoreFeatureAnalysis.Designer.cs @@ -33,12 +33,13 @@ this.CoreTree = new System.Windows.Forms.TreeView(); this.tabControl1 = new System.Windows.Forms.TabControl(); this.tabPage1 = new System.Windows.Forms.TabPage(); + this.CurrentCoreTree = new System.Windows.Forms.TreeView(); this.tabPage2 = new System.Windows.Forms.TabPage(); this.ReleasedCoresLabel = new System.Windows.Forms.Label(); this.label2 = new System.Windows.Forms.Label(); this.TotalCoresLabel = new System.Windows.Forms.Label(); this.label1 = new System.Windows.Forms.Label(); - this.CurrentCoreTree = new System.Windows.Forms.TreeView(); + this.menuStrip1 = new System.Windows.Forms.MenuStrip(); this.tabControl1.SuspendLayout(); this.tabPage1.SuspendLayout(); this.tabPage2.SuspendLayout(); @@ -63,7 +64,7 @@ | System.Windows.Forms.AnchorStyles.Right))); this.CoreTree.Location = new System.Drawing.Point(6, 24); this.CoreTree.Name = "CoreTree"; - this.CoreTree.Size = new System.Drawing.Size(481, 495); + this.CoreTree.Size = new System.Drawing.Size(481, 480); this.CoreTree.TabIndex = 0; // // tabControl1 @@ -73,10 +74,10 @@ | System.Windows.Forms.AnchorStyles.Right))); this.tabControl1.Controls.Add(this.tabPage1); this.tabControl1.Controls.Add(this.tabPage2); - this.tabControl1.Location = new System.Drawing.Point(15, 12); + this.tabControl1.Location = new System.Drawing.Point(15, 27); this.tabControl1.Name = "tabControl1"; this.tabControl1.SelectedIndex = 0; - this.tabControl1.Size = new System.Drawing.Size(501, 551); + this.tabControl1.Size = new System.Drawing.Size(501, 536); this.tabControl1.TabIndex = 6; // // tabPage1 @@ -85,11 +86,21 @@ this.tabPage1.Location = new System.Drawing.Point(4, 22); this.tabPage1.Name = "tabPage1"; this.tabPage1.Padding = new System.Windows.Forms.Padding(3); - this.tabPage1.Size = new System.Drawing.Size(493, 525); + this.tabPage1.Size = new System.Drawing.Size(493, 510); this.tabPage1.TabIndex = 0; this.tabPage1.Text = "Current"; this.tabPage1.UseVisualStyleBackColor = true; // + // CurrentCoreTree + // + this.CurrentCoreTree.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.CurrentCoreTree.Location = new System.Drawing.Point(6, 6); + this.CurrentCoreTree.Name = "CurrentCoreTree"; + this.CurrentCoreTree.Size = new System.Drawing.Size(481, 498); + this.CurrentCoreTree.TabIndex = 1; + // // tabPage2 // this.tabPage2.Controls.Add(this.ReleasedCoresLabel); @@ -100,7 +111,7 @@ this.tabPage2.Location = new System.Drawing.Point(4, 22); this.tabPage2.Name = "tabPage2"; this.tabPage2.Padding = new System.Windows.Forms.Padding(3); - this.tabPage2.Size = new System.Drawing.Size(493, 525); + this.tabPage2.Size = new System.Drawing.Size(493, 510); this.tabPage2.TabIndex = 1; this.tabPage2.Text = "All"; this.tabPage2.UseVisualStyleBackColor = true; @@ -141,15 +152,13 @@ this.label1.TabIndex = 6; this.label1.Text = "Total:"; // - // CurrentCoreTree + // menuStrip1 // - this.CurrentCoreTree.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) - | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.CurrentCoreTree.Location = new System.Drawing.Point(6, 6); - this.CurrentCoreTree.Name = "CurrentCoreTree"; - this.CurrentCoreTree.Size = new System.Drawing.Size(481, 513); - this.CurrentCoreTree.TabIndex = 1; + this.menuStrip1.Location = new System.Drawing.Point(0, 0); + this.menuStrip1.Name = "menuStrip1"; + this.menuStrip1.Size = new System.Drawing.Size(528, 24); + this.menuStrip1.TabIndex = 7; + this.menuStrip1.Text = "menuStrip1"; // // CoreFeatureAnalysis // @@ -160,16 +169,18 @@ this.ClientSize = new System.Drawing.Size(528, 604); this.Controls.Add(this.tabControl1); this.Controls.Add(this.OkBtn); + this.Controls.Add(this.menuStrip1); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); + this.MainMenuStrip = this.menuStrip1; this.Name = "CoreFeatureAnalysis"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; this.Text = "Core Features"; - this.Load += new System.EventHandler(this.CoreFeatureAnalysis_Load); this.tabControl1.ResumeLayout(false); this.tabPage1.ResumeLayout(false); this.tabPage2.ResumeLayout(false); this.tabPage2.PerformLayout(); this.ResumeLayout(false); + this.PerformLayout(); } @@ -185,5 +196,6 @@ private System.Windows.Forms.Label TotalCoresLabel; private System.Windows.Forms.Label label1; private System.Windows.Forms.TreeView CurrentCoreTree; + private System.Windows.Forms.MenuStrip menuStrip1; } } \ No newline at end of file diff --git a/BizHawk.Client.EmuHawk/CoreFeatureAnalysis.cs b/BizHawk.Client.EmuHawk/CoreFeatureAnalysis.cs index d4f86dabe4..77dbeb2178 100644 --- a/BizHawk.Client.EmuHawk/CoreFeatureAnalysis.cs +++ b/BizHawk.Client.EmuHawk/CoreFeatureAnalysis.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Windows.Forms; @@ -10,11 +11,105 @@ using BizHawk.Client.Common; namespace BizHawk.Client.EmuHawk { - public partial class CoreFeatureAnalysis : Form + 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 Services { get; set; } + + public CoreInfo() { } + public CoreInfo(IEmulator emu) + { + TypeName = emu.GetType().ToString(); + CoreName = emu.Attributes().CoreName; + Released = emu.Attributes().Released; + Services = new Dictionary(); + var ser = emu.ServiceProvider; + foreach (Type t in ser.AvailableServices) + { + var si = new ServiceInfo(t, ser.GetService(t)); + Services.Add(si.TypeName, si); + } + } + } + + private class ServiceInfo + { + public string TypeName { get; set; } + public bool Complete { get; set; } + public List 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(); + + IEnumerable 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 KnownCores { get; set; } + [ConfigPersist] + private HashSet KnownServices { get; set; } + + #endregion + + [RequiredService] + IEmulator emu { get; set; } + public CoreFeatureAnalysis() { InitializeComponent(); + KnownCores = new Dictionary(); + KnownServices = new HashSet(); } private void OkBtn_Click(object sender, EventArgs e) @@ -22,208 +117,128 @@ namespace BizHawk.Client.EmuHawk Close(); } - private void CoreFeatureAnalysis_Load(object sender, EventArgs e) + private TreeNode CreateCoreTree(CoreInfo ci) { - DoCurrentCoreTree(); - DoAllCoresTree(); + 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); + } + foreach (string servicename in KnownServices.Where(s => !ci.Services.ContainsKey(s))) + { + 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() + 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); - var core = Global.Emulator; - var services = Assembly - .GetAssembly(typeof(IEmulator)) - .GetTypes() - .Where(t => t.IsInterface) - .Where(t => typeof(IEmulatorService).IsAssignableFrom(t)) - .Where(t => t != typeof(IEmulatorService)) - .ToList(); - - var additionalRegisteredServices = core.ServiceProvider.AvailableServices - .Where(s => !services.Contains(s)) - .Where(s => s != core.GetType()); // We don't care about the core itself - - services.AddRange(additionalRegisteredServices); - CurrentCoreTree.Nodes.Clear(); CurrentCoreTree.BeginUpdate(); - - var coreNode = new TreeNode - { - Text = core.Attributes().CoreName + (core.Attributes().Released ? string.Empty : " (UNRELEASED)"), - ForeColor = core.Attributes().Released ? Color.Black : Color.DarkGray, - }; - - + var coreNode = CreateCoreTree(ci); coreNode.Expand(); - - bool missingImplementation = false; - - foreach (var service in services) - { - bool isImplemented = false; - if (core.ServiceProvider.HasService(service)) - { - isImplemented = true; - } - else if (service.IsAssignableFrom(typeof(ISettable<,>))) // TODO - { - isImplemented = core.GetType() - .GetInterfaces() - .Where(t => t.IsGenericType && - t.GetGenericTypeDefinition() == typeof(ISettable<,>)) - .FirstOrDefault() != null; - } - - var serviceNode = new TreeNode - { - Text = service.Name, - ForeColor = isImplemented ? Color.Black : Color.Red - }; - - bool fullyImplementedInterface = isImplemented; - - if (isImplemented) - { - foreach (var field in service.GetMethods().OrderBy(f => f.Name)) - { - try - { - var coreImplementation = core.ServiceProvider.GetService(service).GetType().GetMethod(field.Name); - - if (coreImplementation != null) - { - var i = coreImplementation.IsImplemented(); - serviceNode.Nodes.Add(new TreeNode - { - Text = field.Name, - ImageKey = i ? "Good" : "Bad", - SelectedImageKey = i ? "Good" : "Bad", - StateImageKey = i ? "Good" : "Bad" - }); - - if (!i) - { - fullyImplementedInterface = false; - } - } - } - catch (Exception) - { - // TODO: SavestateBinary() and SaveStateBinary(BinaryWriter bw) cause an exception, need to look at signature too - } - } - } - else - { - missingImplementation = true; - } - - serviceNode.StateImageKey = serviceNode.SelectedImageKey = serviceNode.ImageKey = fullyImplementedInterface ? "Good" : "Bad"; - - coreNode.Nodes.Add(serviceNode); - } - - coreNode.StateImageKey = coreNode.SelectedImageKey = coreNode.ImageKey = missingImplementation ? "Bad" : "Good"; CurrentCoreTree.Nodes.Add(coreNode); - CurrentCoreTree.EndUpdate(); } - private void DoAllCoresTree() + 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); - var cores = Assembly - .Load("BizHawk.Emulation.Cores") - .GetTypes() - .Where(t => typeof(IEmulator).IsAssignableFrom(t)) - .Select(core => new - { - CoreType = core, - CoreAttributes = core.GetCustomAttributes(false) - .OfType() - .Single(), - ServicesNotApplicable = core.GetCustomAttributes(false) - .OfType() - .SingleOrDefault() ?? new ServiceNotApplicable() - }) - .OrderBy(c => !c.CoreAttributes.Released) - .ThenBy(c => c.CoreAttributes.CoreName) - .ToList(); - - TotalCoresLabel.Text = cores.Count.ToString(); - ReleasedCoresLabel.Text = cores.Count(c => c.CoreAttributes.Released).ToString(); + TotalCoresLabel.Text = KnownCores.Count.ToString(); + ReleasedCoresLabel.Text = KnownCores.Values.Count(c => c.Released).ToString(); CoreTree.Nodes.Clear(); CoreTree.BeginUpdate(); - foreach (var core in cores) + foreach (var ci in KnownCores.Values) { - var coreNode = new TreeNode - { - Text = core.CoreAttributes.CoreName + (core.CoreAttributes.Released ? string.Empty : " (UNRELEASED)"), - ForeColor = core.CoreAttributes.Released ? Color.Black : Color.DarkGray, - }; + var coreNode = CreateCoreTree(ci); - var service = typeof(IEmulator); - - bool isImplemented = false; - if (service.IsAssignableFrom(core.CoreType)) + if (ci.CoreName == current_ci.CoreName) { - isImplemented = true; + coreNode.Expand(); } - - var serviceNode = new TreeNode - { - Text = service.Name, - ForeColor = isImplemented ? Color.Black : Color.Red - }; - - serviceNode.Expand(); - - bool fullyImplementedInterface = isImplemented; - - if (isImplemented) - { - foreach (var field in service.GetMethods().OrderBy(f => f.Name)) - { - var coreImplementation = core.CoreType.GetMethod(field.Name); - - if (coreImplementation != null) - { - var i = coreImplementation.IsImplemented(); - serviceNode.Nodes.Add(new TreeNode - { - Text = field.Name, - ImageKey = i ? "Good" : "Bad", - SelectedImageKey = i ? "Good" : "Bad", - StateImageKey = i ? "Good" : "Bad" - }); - - if (!i) - { - fullyImplementedInterface = false; - } - } - } - } - - serviceNode.StateImageKey = serviceNode.SelectedImageKey = serviceNode.ImageKey = fullyImplementedInterface ? "Good" : "Bad"; - - coreNode.Nodes.Add(serviceNode); - coreNode.StateImageKey = coreNode.SelectedImageKey = coreNode.ImageKey = fullyImplementedInterface ? "Good" : "Bad"; - 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; + + // this will keep phantom services around even when no core implements them, + // which might not be desired? + KnownServices.UnionWith(ci.Services.Keys); + + DoCurrentCoreTree(ci); + DoAllCoresTree(ci); + } + + public bool AskSaveChanges() + { + return true; + } + + public bool UpdateBefore + { + get { return false; } + } + + #endregion } } diff --git a/BizHawk.Client.EmuHawk/CoreFeatureAnalysis.resx b/BizHawk.Client.EmuHawk/CoreFeatureAnalysis.resx index cc815ad657..487177ea6d 100644 --- a/BizHawk.Client.EmuHawk/CoreFeatureAnalysis.resx +++ b/BizHawk.Client.EmuHawk/CoreFeatureAnalysis.resx @@ -117,6 +117,9 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + diff --git a/BizHawk.Client.EmuHawk/MainForm.cs b/BizHawk.Client.EmuHawk/MainForm.cs index 11605353f5..eeac2a8867 100644 --- a/BizHawk.Client.EmuHawk/MainForm.cs +++ b/BizHawk.Client.EmuHawk/MainForm.cs @@ -3656,7 +3656,7 @@ namespace BizHawk.Client.EmuHawk private void FeaturesMenuItem_Click(object sender, EventArgs e) { - new CoreFeatureAnalysis().Show(); + GlobalWin.Tools.Load(); } private void HelpSubMenu_DropDownOpened(object sender, EventArgs e)