Move types for debug menu to own files

This commit is contained in:
YoshiRulz 2022-08-24 04:19:22 +10:00
parent 82c3b471a5
commit 5b859960e9
No known key found for this signature in database
GPG Key ID: C4DE31C245353FB7
5 changed files with 211 additions and 149 deletions

View File

@ -1,18 +1,14 @@
#nullable enable
#if DEBUG
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Client.EmuHawk.ForDebugging;
using BizHawk.Client.EmuHawk.Properties;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores;
using BizHawk.Emulation.Cores.Nintendo.N64;
using BizHawk.Emulation.Cores.Nintendo.Sameboy;
using BizHawk.WinForms.Controls;
@ -20,148 +16,6 @@ namespace BizHawk.Client.EmuHawk
{
public partial class MainForm
{
private sealed class DebugVSystemChildItem : ToolStripMenuItemEx
{
public string? RequiresCore = null;
public bool RequiresLoadedRom = true;
public DebugVSystemChildItem(string labelText, Action onClick)
{
Text = labelText;
Click += (_, _) => onClick();
}
}
private sealed class DebugVSystemMenuItem : ToolStripMenuItemEx
{
public readonly IReadOnlyCollection<string> SysIDs;
public DebugVSystemMenuItem(string labelText, params string[] extraSysIDs)
{
SysIDs = new[] { labelText }.Concat(extraSysIDs).ToHashSet();
Text = labelText;
}
}
private sealed class FirmwareAutopatchDebugToolForm : ToolFormBase
{
public const string TOOL_NAME = "Manual Firmware Autopatching Tool";
protected override string WindowTitleStatic { get; } = TOOL_NAME;
public FirmwareAutopatchDebugToolForm()
{
static string LabelFragment(string hash) => $"{hash.Substring(0, 8)}... {FirmwareDatabase.FirmwareFilesByHash[hash].RecommendedName}";
List<(string Label, FirmwarePatchOption PatchOption)> patches = FirmwareDatabase.AllPatches.Select(static fpo => ($"{LabelFragment(fpo.BaseHash)} --> {LabelFragment(fpo.TargetHash)}", fpo)).ToList();
patches.Sort(static (a, b) => a.Label.CompareTo(b.Label));
ComboBox comboPatchsets = new() { Size = new(300, 23) };
foreach (var tuple in patches) comboPatchsets.Items.Add(tuple.Label);
SzTextBoxEx txtBaseFile = new() { Size = new(224, 23) };
SzButtonEx btnBaseFilePicker = new() { Size = new(75, 23), Text = "(browse)" };
btnBaseFilePicker.Click += (_, _) =>
{
using OpenFileDialog ofd = new() { InitialDirectory = Config!.PathEntries.FirmwareAbsolutePath() };
this.ShowDialogAsChild(ofd);
txtBaseFile.Text = ofd.FileName;
};
CheckBoxEx cbDryRun = new() { Checked = true, Text = "dry run (skip writing to disk)" };
SzButtonEx btnPatch = new() { Size = new(75, 23), Text = "--> patch" };
btnPatch.Click += (_, _) =>
{
var fpo = patches[comboPatchsets.SelectedIndex].PatchOption;
try
{
if (!cbDryRun.Checked)
{
var (filePath, _, _) = FirmwareManager.PerformPatchOnDisk(txtBaseFile.Text, in fpo, Config!.PathEntries);
// if the base file (or patchset) is wrong, too bad
this.ModalMessageBox($"wrote {filePath}");
return;
}
var @base = File.ReadAllBytes(txtBaseFile.Text);
var (_, actualHash) = FirmwareManager.PerformPatchInMemory(@base, in fpo);
if (actualHash == fpo.TargetHash)
{
this.ModalMessageBox("success");
return;
}
// else something happened, figure out what it was
var baseHash = SHA1Checksum.ComputeDigestHex(@base);
this.ModalMessageBox(baseHash == fpo.BaseHash
? $"patchset declared with target\nSHA1:{fpo.TargetHash}\nbut produced\nSHA1:{actualHash}\n(is the patch wrong, or the hash?)"
: $"patchset declared for base\nSHA1:{fpo.BaseHash}\nbut\nSHA1:{baseHash}\nwas provided");
}
catch (Exception e)
{
this.ModalMessageBox($"caught {e.GetType().Name}:\n{e}");
}
};
ClientSize = new(320, 200);
SuspendLayout();
Controls.Add(new SingleColumnFLP
{
Controls =
{
new LabelEx { Text = "apply" },
comboPatchsets,
new LabelEx { Text = "to file" },
new SingleRowFLP { Controls = { txtBaseFile, btnBaseFilePicker } },
cbDryRun,
new LabelEx { Text = "patched files are saved in dir set as \"Temp Files\"" },
btnPatch,
}
});
ResumeLayout();
}
}
private sealed class N64VideoSettingsFuzzToolForm : ToolFormBase
{
public const string TOOL_NAME = "N64 Video Settings Fuzzer";
[RequiredService]
private IEmulator? Emulator { get; set; }
protected override string WindowTitleStatic { get; } = TOOL_NAME;
public N64VideoSettingsFuzzToolForm()
{
ClientSize = new(240, 96);
SuspendLayout();
// don't think the other plugins are even worth testing anymore, but this could easily be expanded to include them all --yoshi
ComboBox comboPlugin = new() { Enabled = false, Items = { "GLideN64" }, SelectedIndex = 0 };
Dictionary<PropertyInfo, IReadOnlyList<object>> propDict = new();
foreach (var pi in typeof(N64SyncSettings.N64GLideN64PluginSettings).GetProperties())
{
if (pi.PropertyType == typeof(bool)) propDict[pi] = new object[] { true, false };
else if (pi.PropertyType.IsEnum) propDict[pi] = Enum.GetValues(pi.PropertyType).Cast<object>().ToArray();
}
static object RandomElem(IReadOnlyList<object> a, Random rng) => a[rng.Next(a.Count)];
Random rng = new();
void Fuzz(bool limit)
{
var props = propDict.Keys.ToList();
if (limit)
{
props.Sort((_, _) => rng.Next(2));
var l = props.Count / 10;
while (l < props.Count) props.RemoveAt(l);
}
var ss = ((N64) Emulator!).GetSyncSettings();
var glidenSS = ss.GLideN64Plugin;
foreach (var pi in props) pi.SetValue(obj: glidenSS, value: RandomElem(propDict[pi], rng));
((MainForm) MainForm).GetSettingsAdapterForLoadedCore<N64>().PutCoreSyncSettings(ss);
}
SzButtonEx btnLightFuzz = new() { Size = new(200, 23), Text = "--> randomise some props" };
btnLightFuzz.Click += (_, _) => Fuzz(limit: true);
SzButtonEx btnHeavyFuzz = new() { Size = new(200, 23), Text = "--> randomise every prop" };
btnHeavyFuzz.Click += (_, _) => Fuzz(limit: false);
Controls.Add(new SingleColumnFLP { Controls = { comboPlugin, btnLightFuzz, btnHeavyFuzz } });
ResumeLayout();
}
}
private void AddDebugMenu()
{
// void OpenModal<T>()

View File

@ -0,0 +1,45 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using BizHawk.WinForms.Controls;
namespace BizHawk.Client.EmuHawk.ForDebugging
{
internal sealed class DebugVSystemChildItem : ToolStripMenuItemEx
{
public string? RequiresCore = null;
public bool RequiresLoadedRom = true;
public DebugVSystemChildItem(string labelText, Action onClick)
{
Text = labelText;
Click += (_, _) => onClick();
}
}
internal sealed class DebugVSystemMenuItem : ToolStripMenuItemEx
{
public readonly IReadOnlyCollection<string> SysIDs;
public DebugVSystemMenuItem(string sysID, params string[] extraSysIDs)
{
SysIDs = new[] { sysID }.Concat(extraSysIDs).ToHashSet();
Text = sysID;
}
}
internal static class GenControl
{
public static Button Button(string text, int width, Action onClick)
{
SzButtonEx btn = new() { Size = new(width, 23), Text = text };
btn.Click += (_, _) => onClick();
return btn;
}
}
}

View File

@ -0,0 +1,88 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using BizHawk.Client.Common;
using BizHawk.Common;
using BizHawk.Emulation.Common;
using BizHawk.WinForms.Controls;
namespace BizHawk.Client.EmuHawk.ForDebugging
{
internal sealed class FirmwareAutopatchDebugToolForm : ToolFormBase
{
public const string TOOL_NAME = "Manual Firmware Autopatching Tool";
protected override string WindowTitleStatic
=> TOOL_NAME;
public FirmwareAutopatchDebugToolForm()
{
static string LabelFragment(string hash)
=> $"{hash.Substring(0, 8)}... {FirmwareDatabase.FirmwareFilesByHash[hash].RecommendedName}";
List<(string Label, FirmwarePatchOption PatchOption)> patches = FirmwareDatabase.AllPatches
.Select(static fpo => ($"{LabelFragment(fpo.BaseHash)} --> {LabelFragment(fpo.TargetHash)}", fpo)).ToList();
patches.Sort(static (a, b) => a.Label.CompareTo(b.Label));
ComboBox comboPatchsets = new() { Size = new(300, 23) };
foreach (var tuple in patches) comboPatchsets.Items.Add(tuple.Label);
SzTextBoxEx txtBaseFile = new() { Size = new(224, 23) };
void ShowBaseFilePicker()
{
using OpenFileDialog ofd = new() { InitialDirectory = Config!.PathEntries.FirmwareAbsolutePath() };
this.ShowDialogAsChild(ofd);
txtBaseFile.Text = ofd.FileName;
}
CheckBoxEx cbDryRun = new() { Checked = true, Text = "dry run (skip writing to disk)" };
void DoPatch()
{
var fpo = patches[comboPatchsets.SelectedIndex].PatchOption;
try
{
if (!cbDryRun.Checked)
{
var (filePath, _, _) = FirmwareManager.PerformPatchOnDisk(txtBaseFile.Text, in fpo, Config!.PathEntries);
// if the base file (or patchset) is wrong, too bad
this.ModalMessageBox($"wrote {filePath}");
return;
}
var @base = File.ReadAllBytes(txtBaseFile.Text);
var (_, actualHash) = FirmwareManager.PerformPatchInMemory(@base, in fpo);
if (actualHash == fpo.TargetHash)
{
this.ModalMessageBox("success");
return;
}
// else something happened, figure out what it was
var baseHash = SHA1Checksum.ComputeDigestHex(@base);
this.ModalMessageBox(baseHash == fpo.BaseHash
? $"patchset declared with target\nSHA1:{fpo.TargetHash}\nbut produced\nSHA1:{actualHash}\n(is the patch wrong, or the hash?)"
: $"patchset declared for base\nSHA1:{fpo.BaseHash}\nbut\nSHA1:{baseHash}\nwas provided");
}
catch (Exception e)
{
this.ModalMessageBox($"caught {e.GetType().Name}:\n{e}");
}
}
ClientSize = new(320, 200);
SuspendLayout();
Controls.Add(new SingleColumnFLP
{
Controls =
{
new LabelEx { Text = "apply" },
comboPatchsets,
new LabelEx { Text = "to file" },
new SingleRowFLP { Controls = { txtBaseFile, GenControl.Button("(browse)", width: 75, ShowBaseFilePicker) } },
cbDryRun,
new LabelEx { Text = "patched files are saved in dir set as \"Temp Files\"" },
GenControl.Button("--> patch", width: 75, DoPatch),
},
});
ResumeLayout();
}
}
}

View File

@ -0,0 +1,72 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using BizHawk.Emulation.Common;
using BizHawk.Emulation.Cores.Nintendo.N64;
using BizHawk.WinForms.Controls;
namespace BizHawk.Client.EmuHawk.ForDebugging
{
internal sealed class N64VideoSettingsFuzzToolForm : ToolFormBase
{
public const string TOOL_NAME = "N64 Video Settings Fuzzer";
[RequiredService]
private N64? _maybeEmulator { get; set; } = null;
private N64 Emulator
=> _maybeEmulator!;
protected override string WindowTitleStatic
=> TOOL_NAME;
public N64VideoSettingsFuzzToolForm()
{
ClientSize = new(240, 96);
SuspendLayout();
#if true // don't think the other plugins are even worth testing anymore, but this could easily be expanded to include them --yoshi
ComboBox comboPlugin = new() { Enabled = false, Items = { "GLideN64" }, SelectedIndex = 0 };
#else
ComboBox comboPlugin = new() { Items = { "GLideN64" } };
#endif
Dictionary<PropertyInfo, IReadOnlyList<object?>> propDict = new();
foreach (var pi in typeof(N64SyncSettings.N64GLideN64PluginSettings).GetProperties())
{
if (pi.PropertyType == typeof(bool)) propDict[pi] = new object?[] { true, false };
else if (pi.PropertyType.IsEnum) propDict[pi] = Enum.GetValues(pi.PropertyType).Cast<object?>().ToArray();
}
static object? RandomElem(IReadOnlyList<object?> a, Random rng)
=> a[rng.Next(a.Count)];
Random rng = new();
void Fuzz(bool limit)
{
var props = propDict.Keys.ToList();
if (limit)
{
props.Sort((_, _) => rng.Next(2));
var l = props.Count / 10;
while (l < props.Count) props.RemoveAt(l);
}
var ss = Emulator.GetSyncSettings();
var glidenSS = ss.GLideN64Plugin;
foreach (var pi in props) pi.SetValue(obj: glidenSS, value: RandomElem(propDict[pi], rng));
((MainForm) MainForm).GetSettingsAdapterForLoadedCore<N64>().PutCoreSyncSettings(ss);
}
Controls.Add(new SingleColumnFLP
{
Controls =
{
comboPlugin,
GenControl.Button("--> randomise some props", width: 200, () => Fuzz(limit: true)),
GenControl.Button("--> randomise every prop", width: 200, () => Fuzz(limit: false)),
},
});
ResumeLayout();
}
}
}

View File

@ -13,4 +13,7 @@
<ItemGroup>
<Analyzer Include="$(ProjectDir)../../References/BizHawk.SrcGen.ReflectionCache.dll" />
</ItemGroup>
<ItemGroup Condition=" '$(Configuration)' != 'Debug' ">
<Compile Remove="$(ProjectDir)debug/**/*" />
</ItemGroup>
</Project>