Cheats: Added basic cheat code finder tool

This commit is contained in:
Souryo 2016-08-25 19:02:33 -04:00
parent 9d239daf3c
commit ccc2fc2aa3
24 changed files with 1229 additions and 31 deletions

View file

@ -448,10 +448,10 @@ void Console::LoadState(uint8_t *buffer, uint32_t bufferSize)
LoadState(stream);
}
std::shared_ptr<Debugger> Console::GetDebugger()
std::shared_ptr<Debugger> Console::GetDebugger(bool autoStart)
{
auto lock = _debuggerLock.AcquireSafe();
if(!_debugger) {
if(!_debugger && autoStart) {
_debugger.reset(new Debugger(Console::Instance, _cpu, _ppu, _memoryManager, _mapper));
}
return _debugger;

View file

@ -59,7 +59,7 @@ class Console
//Used to resume the emu loop after calling Pause()
static void Resume();
std::shared_ptr<Debugger> GetDebugger();
std::shared_ptr<Debugger> GetDebugger(bool autoStart = true);
void StopDebugger();
static NesModel GetNesModel();

View file

@ -597,6 +597,12 @@ uint32_t Debugger::GetMemoryState(DebugMemoryType type, uint8_t *buffer)
memcpy(buffer, chrRam, _mapper->GetChrSize(true));
delete[] chrRam;
return _mapper->GetChrSize(true);
case DebugMemoryType::InternalRam:
for(int i = 0; i < 0x800; i++) {
buffer[i] = _memoryManager->DebugRead(i);
}
return 0x800;
}
return 0;
}

View file

@ -28,6 +28,7 @@ enum class DebugMemoryType
PrgRom = 5,
ChrRom = 6,
ChrRam = 7,
InternalRam = 8,
};
enum class DebuggerFlags

View file

@ -0,0 +1,81 @@
namespace Mesen.GUI.Debugger.Controls
{
partial class ctrlAddressList
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.ctrlDataViewer = new Mesen.GUI.Debugger.ctrlScrollableTextbox();
this.toolTip = new System.Windows.Forms.ToolTip(this.components);
this.tableLayoutPanel1.SuspendLayout();
this.SuspendLayout();
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 1;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Controls.Add(this.ctrlDataViewer, 0, 1);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 2;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.Size = new System.Drawing.Size(191, 109);
this.tableLayoutPanel1.TabIndex = 0;
//
// ctrlDataViewer
//
this.ctrlDataViewer.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.ctrlDataViewer.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlDataViewer.FontSize = 13F;
this.ctrlDataViewer.Location = new System.Drawing.Point(3, 3);
this.ctrlDataViewer.Name = "ctrlDataViewer";
this.ctrlDataViewer.ShowContentNotes = false;
this.ctrlDataViewer.ShowLineNumberNotes = false;
this.ctrlDataViewer.Size = new System.Drawing.Size(185, 103);
this.ctrlDataViewer.TabIndex = 0;
//
// ctrlAddressList
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.tableLayoutPanel1);
this.Name = "ctrlAddressList";
this.Size = new System.Drawing.Size(191, 109);
this.tableLayoutPanel1.ResumeLayout(false);
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private ctrlScrollableTextbox ctrlDataViewer;
private System.Windows.Forms.ToolTip toolTip;
}
}

View file

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Config;
namespace Mesen.GUI.Debugger.Controls
{
public partial class ctrlAddressList : BaseScrollableTextboxUserControl
{
private int[] _addresses;
public ctrlAddressList()
{
InitializeComponent();
this.ctrlDataViewer.MarginWidth = 3;
}
protected override ctrlScrollableTextbox ScrollableTextbox
{
get { return this.ctrlDataViewer; }
}
public void SetData(byte[] values, int[] addresses)
{
this.ctrlDataViewer.Header = null;
this.ctrlDataViewer.TextLines = values.Select(val => val.ToString("X2")).ToArray();
this.ctrlDataViewer.LineNumbers = addresses;
_addresses = addresses;
}
public int? CurrentAddress
{
get
{
if(_addresses?.Length > 0) {
return _addresses[Math.Min(this.ctrlDataViewer.CurrentLine, _addresses.Length - 1)];
} else {
return null;
}
}
}
}
}

View file

@ -0,0 +1,123 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="toolTip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
</root>

View file

@ -250,6 +250,8 @@ namespace Mesen.GUI.Debugger
}
}
public int MarginWidth { set { this.ctrlTextbox.MarginWidth = value; } }
public void OpenSearchBox(bool forceFocus = false)
{
bool focus = !this.panelSearch.Visible;

View file

@ -48,6 +48,7 @@ namespace Mesen.GUI.Debugger
private string _searchString = null;
private string _header = null;
private Font _noteFont = null;
private int _marginWidth = 6;
public ctrlTextbox()
{
@ -159,6 +160,15 @@ namespace Mesen.GUI.Debugger
}
}
public int MarginWidth
{
set
{
this._marginWidth = value;
this.Invalidate();
}
}
public bool Search(string searchString, bool searchBackwards, bool isNewSearch)
{
if(string.IsNullOrWhiteSpace(searchString)) {
@ -284,7 +294,7 @@ namespace Mesen.GUI.Debugger
private int GetMargin(Graphics g)
{
return this.ShowLineNumbers ? (int)(g.MeasureString("W", this.Font).Width * 6) : 0;
return this.ShowLineNumbers ? (int)(g.MeasureString("W", this.Font).Width * _marginWidth) : 0;
}
public int GetLineIndexAtPosition(int yPos)
@ -369,7 +379,7 @@ namespace Mesen.GUI.Debugger
get { return Math.Min(this._contents.Length - 1, Math.Max(0, _cursorPosition)); }
set
{
_cursorPosition = Math.Min(this._contents.Length - 1, Math.Max(0, value));
_cursorPosition = Math.Max(0, Math.Min(this._contents.Length - 1, Math.Max(0, value)));
if(_cursorPosition < this.ScrollPosition) {
this.ScrollPosition = _cursorPosition;
} else if(_cursorPosition > this.GetLastVisibleLineIndex()) {

View file

@ -130,5 +130,17 @@
<Value ID="AllOnes">All 1s</Value>
<Value ID="Random">Random Values</Value>
</Enum>
<Enum ID="CheatCurrentFilterType">
<Value ID="Smaller">Smaller than</Value>
<Value ID="Equal">Equal to</Value>
<Value ID="NotEqual">Not equal to</Value>
<Value ID="Greater">Greater than</Value>
</Enum>
<Enum ID="CheatPrevFilterType">
<Value ID="Smaller">Smaller</Value>
<Value ID="Equal">Equal</Value>
<Value ID="NotEqual">Not equal</Value>
<Value ID="Greater">Greater</Value>
</Enum>
</Enums>
</Resources>

View file

@ -364,6 +364,19 @@
<Control ID="btnExportSelectedCheats">Exporter les codes sélectionnés</Control>
<Control ID="mnuExportSelectedCheats">Exporter</Control>
<Control ID="chkDisableCheats">Désactiver tous les codes</Control>
<Control ID="tpgCheatFinder">Recherche de codes</Control>
<Control ID="btnReset">Réinitialiser</Control>
<Control ID="btnUndo">Annuler</Control>
<Control ID="lblCurrentValue">La valeur courante est</Control>
<Control ID="lblPreviousValue">La valeur précédente était</Control>
<Control ID="btnAddCurrentFilter">Ajouter le filtre</Control>
<Control ID="btnAddPrevFilter">Ajouter le filtre</Control>
<Control ID="btnCreateCheat">Créer un code</Control>
<Control ID="mnuCreateCheat">Créer un code</Control>
<Control ID="lblAtAddress">à</Control>
<Control ID="chkPauseGameWhileWindowActive">Mettre le jeu à pause automatiquement lorsque cette fenêtre est active</Control>
<Control ID="btnOK">OK</Control>
<Control ID="btnCancel">Annuler</Control>
</Form>
@ -540,5 +553,17 @@
<Value ID="AllOnes">Tous les bits à 1</Value>
<Value ID="Random">Valeurs aléatoires</Value>
</Enum>
<Enum ID="CheatCurrentFilterType">
<Value ID="Smaller">Plus petite que</Value>
<Value ID="Equal">Égale à</Value>
<Value ID="NotEqual">Pas égale à</Value>
<Value ID="Greater">Plus grand que</Value>
</Enum>
<Enum ID="CheatPrevFilterType">
<Value ID="Smaller">Plus petite</Value>
<Value ID="Equal">Égale</Value>
<Value ID="NotEqual">Pas égale</Value>
<Value ID="Greater">Plus grande</Value>
</Enum>
</Enums>
</Resources>

View file

@ -352,6 +352,19 @@
<Control ID="btnExportSelectedCheats">選択中のコードをエクスポートする</Control>
<Control ID="mnuExportSelectedCheats">エクスポート</Control>
<Control ID="chkDisableCheats">チートコード機能を無効にする</Control>
<Control ID="tpgCheatFinder">コードファインダー</Control>
<Control ID="btnReset">リセット</Control>
<Control ID="btnUndo">元に戻す</Control>
<Control ID="lblCurrentValue">現在の数値は</Control>
<Control ID="lblPreviousValue">前回の数値は現在の数値</Control>
<Control ID="btnAddCurrentFilter">フィルター追加</Control>
<Control ID="btnAddPrevFilter">フィルター追加</Control>
<Control ID="btnCreateCheat">コード作成</Control>
<Control ID="mnuCreateCheat">コード作成</Control>
<Control ID="lblAtAddress"></Control>
<Control ID="chkPauseGameWhileWindowActive">このウィンドウがアクティブの時、自動的にゲームをポーズする</Control>
<Control ID="btnOK">OK</Control>
<Control ID="btnCancel">キャンセル</Control>
</Form>
@ -523,5 +536,17 @@
<Value ID="AllOnes">ビット全てを1にする</Value>
<Value ID="Random">乱数</Value>
</Enum>
<Enum ID="CheatCurrentFilterType">
<Value ID="Smaller">次の数値より小さい</Value>
<Value ID="Equal">次の数値と同じ</Value>
<Value ID="NotEqual">次の数値とは違う</Value>
<Value ID="Greater">次の数値より大きい</Value>
</Enum>
<Enum ID="CheatPrevFilterType">
<Value ID="Smaller">より小さい</Value>
<Value ID="Equal">と同じ</Value>
<Value ID="NotEqual">とは違う</Value>
<Value ID="Greater">より大きい</Value>
</Enum>
</Enums>
</Resources>

View file

@ -114,6 +114,15 @@ namespace Mesen.GUI.Forms
AddBinding(fieldName, trueRadio);
}
public static void InitializeComboBox(ComboBox combo, Type enumType)
{
combo.DropDownStyle = ComboBoxStyle.DropDownList;
combo.Items.Clear();
foreach(Enum value in Enum.GetValues(enumType)) {
combo.Items.Add(ResourceHelper.GetEnumText(value));
}
}
protected void AddBinding(string fieldName, Control bindedField)
{
if(BindedType == null) {
@ -131,12 +140,7 @@ namespace Mesen.GUI.Forms
if(_fieldInfo.ContainsKey(fieldName)) {
Type fieldType = _fieldInfo[fieldName].FieldType;
if(fieldType.IsSubclassOf(typeof(Enum)) && bindedField is ComboBox) {
ComboBox combo = ((ComboBox)bindedField);
combo.DropDownStyle = ComboBoxStyle.DropDownList;
combo.Items.Clear();
foreach(Enum value in Enum.GetValues(fieldType)) {
combo.Items.Add(ResourceHelper.GetEnumText(value));
}
InitializeComboBox(((ComboBox)bindedField), fieldType);
}
_bindings[fieldName] = bindedField;
} else {

View file

@ -31,9 +31,23 @@ namespace Mesen.GUI.Forms
this.Icon = menuItem.Image;
}
if(owner != null) {
CenterOnParent(owner);
}
base.Show(owner);
}
private void CenterOnParent(IWin32Window owner)
{
Form parent = (Form)owner;
Point point = parent.PointToScreen(new Point(parent.Width / 2, parent.Height / 2));
this.StartPosition = FormStartPosition.Manual;
this.Top = point.Y - this.Height / 2;
this.Left = point.X - this.Width / 2;
}
public DialogResult ShowDialog(object sender, IWin32Window owner = null)
{
if(sender is ToolStripMenuItem) {

View file

@ -0,0 +1,368 @@
namespace Mesen.GUI.Forms.Cheats
{
partial class ctrlCheatFinder
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if(disposing && (components != null)) {
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.components = new System.ComponentModel.Container();
this.tmrRefresh = new System.Windows.Forms.Timer(this.components);
this.grpFilters = new System.Windows.Forms.GroupBox();
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
this.flowLayoutPanel1 = new System.Windows.Forms.FlowLayoutPanel();
this.lblPreviousValue = new System.Windows.Forms.Label();
this.cboPrevFilterType = new System.Windows.Forms.ComboBox();
this.btnAddPrevFilter = new System.Windows.Forms.Button();
this.flowLayoutPanel4 = new System.Windows.Forms.FlowLayoutPanel();
this.lblCurrentValue = new System.Windows.Forms.Label();
this.cboCurrentFilterType = new System.Windows.Forms.ComboBox();
this.nudCurrentFilterValue = new System.Windows.Forms.NumericUpDown();
this.btnAddCurrentFilter = new System.Windows.Forms.Button();
this.btnReset = new System.Windows.Forms.Button();
this.btnUndo = new System.Windows.Forms.Button();
this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
this.lstAddresses = new Mesen.GUI.Debugger.Controls.ctrlAddressList();
this.contextMenuStrip = new System.Windows.Forms.ContextMenuStrip(this.components);
this.mnuCreateCheat = new System.Windows.Forms.ToolStripMenuItem();
this.flowLayoutPanel2 = new System.Windows.Forms.FlowLayoutPanel();
this.btnCreateCheat = new System.Windows.Forms.Button();
this.lblAtAddress = new System.Windows.Forms.Label();
this.lblAddress = new System.Windows.Forms.Label();
this.chkPauseGameWhileWindowActive = new System.Windows.Forms.CheckBox();
this.grpFilters.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.flowLayoutPanel1.SuspendLayout();
this.flowLayoutPanel4.SuspendLayout();
((System.ComponentModel.ISupportInitialize)(this.nudCurrentFilterValue)).BeginInit();
this.tableLayoutPanel1.SuspendLayout();
this.contextMenuStrip.SuspendLayout();
this.flowLayoutPanel2.SuspendLayout();
this.SuspendLayout();
//
// tmrRefresh
//
this.tmrRefresh.Enabled = true;
this.tmrRefresh.Tick += new System.EventHandler(this.tmrRefresh_Tick);
//
// grpFilters
//
this.grpFilters.Controls.Add(this.tableLayoutPanel2);
this.grpFilters.Dock = System.Windows.Forms.DockStyle.Fill;
this.grpFilters.Location = new System.Drawing.Point(3, 3);
this.grpFilters.Name = "grpFilters";
this.grpFilters.Size = new System.Drawing.Size(399, 160);
this.grpFilters.TabIndex = 4;
this.grpFilters.TabStop = false;
this.grpFilters.Text = "Filters";
//
// tableLayoutPanel2
//
this.tableLayoutPanel2.ColumnCount = 2;
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.Controls.Add(this.flowLayoutPanel1, 0, 2);
this.tableLayoutPanel2.Controls.Add(this.flowLayoutPanel4, 0, 1);
this.tableLayoutPanel2.Controls.Add(this.btnReset, 0, 0);
this.tableLayoutPanel2.Controls.Add(this.btnUndo, 1, 0);
this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel2.Location = new System.Drawing.Point(3, 16);
this.tableLayoutPanel2.Name = "tableLayoutPanel2";
this.tableLayoutPanel2.RowCount = 4;
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F));
this.tableLayoutPanel2.Size = new System.Drawing.Size(393, 141);
this.tableLayoutPanel2.TabIndex = 13;
//
// flowLayoutPanel1
//
this.tableLayoutPanel2.SetColumnSpan(this.flowLayoutPanel1, 2);
this.flowLayoutPanel1.Controls.Add(this.lblPreviousValue);
this.flowLayoutPanel1.Controls.Add(this.cboPrevFilterType);
this.flowLayoutPanel1.Controls.Add(this.btnAddPrevFilter);
this.flowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel1.Location = new System.Drawing.Point(0, 59);
this.flowLayoutPanel1.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel1.Name = "flowLayoutPanel1";
this.flowLayoutPanel1.Size = new System.Drawing.Size(393, 31);
this.flowLayoutPanel1.TabIndex = 1;
//
// lblPreviousValue
//
this.lblPreviousValue.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblPreviousValue.AutoSize = true;
this.lblPreviousValue.Location = new System.Drawing.Point(3, 8);
this.lblPreviousValue.Name = "lblPreviousValue";
this.lblPreviousValue.Size = new System.Drawing.Size(99, 13);
this.lblPreviousValue.TabIndex = 3;
this.lblPreviousValue.Text = "Previous value was";
//
// cboPrevFilterType
//
this.cboPrevFilterType.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.cboPrevFilterType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboPrevFilterType.FormattingEnabled = true;
this.cboPrevFilterType.Location = new System.Drawing.Point(108, 4);
this.cboPrevFilterType.Name = "cboPrevFilterType";
this.cboPrevFilterType.Size = new System.Drawing.Size(110, 21);
this.cboPrevFilterType.TabIndex = 0;
//
// btnAddPrevFilter
//
this.btnAddPrevFilter.AutoSize = true;
this.btnAddPrevFilter.Location = new System.Drawing.Point(224, 3);
this.btnAddPrevFilter.Name = "btnAddPrevFilter";
this.btnAddPrevFilter.Size = new System.Drawing.Size(75, 23);
this.btnAddPrevFilter.TabIndex = 2;
this.btnAddPrevFilter.Text = "Add Filter";
this.btnAddPrevFilter.UseVisualStyleBackColor = true;
this.btnAddPrevFilter.Click += new System.EventHandler(this.btnAddPrevFilter_Click);
//
// flowLayoutPanel4
//
this.tableLayoutPanel2.SetColumnSpan(this.flowLayoutPanel4, 2);
this.flowLayoutPanel4.Controls.Add(this.lblCurrentValue);
this.flowLayoutPanel4.Controls.Add(this.cboCurrentFilterType);
this.flowLayoutPanel4.Controls.Add(this.nudCurrentFilterValue);
this.flowLayoutPanel4.Controls.Add(this.btnAddCurrentFilter);
this.flowLayoutPanel4.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel4.Location = new System.Drawing.Point(0, 29);
this.flowLayoutPanel4.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel4.Name = "flowLayoutPanel4";
this.flowLayoutPanel4.Size = new System.Drawing.Size(393, 30);
this.flowLayoutPanel4.TabIndex = 0;
//
// lblCurrentValue
//
this.lblCurrentValue.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblCurrentValue.AutoSize = true;
this.lblCurrentValue.Location = new System.Drawing.Point(3, 8);
this.lblCurrentValue.Name = "lblCurrentValue";
this.lblCurrentValue.Size = new System.Drawing.Size(80, 13);
this.lblCurrentValue.TabIndex = 4;
this.lblCurrentValue.Text = "Current value is";
//
// cboCurrentFilterType
//
this.cboCurrentFilterType.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.cboCurrentFilterType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
this.cboCurrentFilterType.FormattingEnabled = true;
this.cboCurrentFilterType.Location = new System.Drawing.Point(89, 4);
this.cboCurrentFilterType.Name = "cboCurrentFilterType";
this.cboCurrentFilterType.Size = new System.Drawing.Size(110, 21);
this.cboCurrentFilterType.TabIndex = 0;
//
// nudCurrentFilterValue
//
this.nudCurrentFilterValue.Location = new System.Drawing.Point(205, 5);
this.nudCurrentFilterValue.Margin = new System.Windows.Forms.Padding(3, 5, 3, 3);
this.nudCurrentFilterValue.Maximum = new decimal(new int[] {
255,
0,
0,
0});
this.nudCurrentFilterValue.Name = "nudCurrentFilterValue";
this.nudCurrentFilterValue.Size = new System.Drawing.Size(41, 20);
this.nudCurrentFilterValue.TabIndex = 1;
//
// btnAddCurrentFilter
//
this.btnAddCurrentFilter.AutoSize = true;
this.btnAddCurrentFilter.Location = new System.Drawing.Point(252, 3);
this.btnAddCurrentFilter.Name = "btnAddCurrentFilter";
this.btnAddCurrentFilter.Size = new System.Drawing.Size(75, 23);
this.btnAddCurrentFilter.TabIndex = 2;
this.btnAddCurrentFilter.Text = "Add Filter";
this.btnAddCurrentFilter.UseVisualStyleBackColor = true;
this.btnAddCurrentFilter.Click += new System.EventHandler(this.btnAddCurrentFilter_Click);
//
// btnReset
//
this.btnReset.Location = new System.Drawing.Point(3, 3);
this.btnReset.Name = "btnReset";
this.btnReset.Size = new System.Drawing.Size(75, 23);
this.btnReset.TabIndex = 5;
this.btnReset.Text = "Reset";
this.btnReset.UseVisualStyleBackColor = true;
this.btnReset.Click += new System.EventHandler(this.btnReset_Click);
//
// btnUndo
//
this.btnUndo.Location = new System.Drawing.Point(84, 3);
this.btnUndo.Name = "btnUndo";
this.btnUndo.Size = new System.Drawing.Size(75, 23);
this.btnUndo.TabIndex = 11;
this.btnUndo.Text = "Undo";
this.btnUndo.UseVisualStyleBackColor = true;
this.btnUndo.Click += new System.EventHandler(this.btnUndo_Click);
//
// tableLayoutPanel1
//
this.tableLayoutPanel1.ColumnCount = 2;
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
this.tableLayoutPanel1.Controls.Add(this.grpFilters, 0, 0);
this.tableLayoutPanel1.Controls.Add(this.lstAddresses, 1, 0);
this.tableLayoutPanel1.Controls.Add(this.flowLayoutPanel2, 1, 1);
this.tableLayoutPanel1.Controls.Add(this.chkPauseGameWhileWindowActive, 0, 1);
this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
this.tableLayoutPanel1.Name = "tableLayoutPanel1";
this.tableLayoutPanel1.RowCount = 2;
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle());
this.tableLayoutPanel1.Size = new System.Drawing.Size(565, 196);
this.tableLayoutPanel1.TabIndex = 5;
//
// lstAddresses
//
this.lstAddresses.ContextMenuStrip = this.contextMenuStrip;
this.lstAddresses.Dock = System.Windows.Forms.DockStyle.Fill;
this.lstAddresses.Location = new System.Drawing.Point(408, 3);
this.lstAddresses.Name = "lstAddresses";
this.lstAddresses.Size = new System.Drawing.Size(154, 160);
this.lstAddresses.TabIndex = 3;
//
// contextMenuStrip
//
this.contextMenuStrip.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
this.mnuCreateCheat});
this.contextMenuStrip.Name = "contextMenuStrip";
this.contextMenuStrip.Size = new System.Drawing.Size(143, 26);
this.contextMenuStrip.Opening += new System.ComponentModel.CancelEventHandler(this.contextMenuStrip_Opening);
//
// mnuCreateCheat
//
this.mnuCreateCheat.Name = "mnuCreateCheat";
this.mnuCreateCheat.Size = new System.Drawing.Size(142, 22);
this.mnuCreateCheat.Text = "Create Cheat";
this.mnuCreateCheat.Click += new System.EventHandler(this.btnCreateCheat_Click);
//
// flowLayoutPanel2
//
this.flowLayoutPanel2.Controls.Add(this.btnCreateCheat);
this.flowLayoutPanel2.Controls.Add(this.lblAtAddress);
this.flowLayoutPanel2.Controls.Add(this.lblAddress);
this.flowLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill;
this.flowLayoutPanel2.Location = new System.Drawing.Point(405, 166);
this.flowLayoutPanel2.Margin = new System.Windows.Forms.Padding(0);
this.flowLayoutPanel2.Name = "flowLayoutPanel2";
this.flowLayoutPanel2.Size = new System.Drawing.Size(160, 30);
this.flowLayoutPanel2.TabIndex = 5;
//
// btnCreateCheat
//
this.btnCreateCheat.Location = new System.Drawing.Point(3, 3);
this.btnCreateCheat.Name = "btnCreateCheat";
this.btnCreateCheat.Size = new System.Drawing.Size(85, 23);
this.btnCreateCheat.TabIndex = 5;
this.btnCreateCheat.Text = "Create Cheat";
this.btnCreateCheat.UseVisualStyleBackColor = true;
this.btnCreateCheat.Click += new System.EventHandler(this.btnCreateCheat_Click);
//
// lblAtAddress
//
this.lblAtAddress.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblAtAddress.AutoSize = true;
this.lblAtAddress.Location = new System.Drawing.Point(94, 8);
this.lblAtAddress.Name = "lblAtAddress";
this.lblAtAddress.Size = new System.Drawing.Size(16, 13);
this.lblAtAddress.TabIndex = 6;
this.lblAtAddress.Text = "at";
//
// lblAddress
//
this.lblAddress.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.lblAddress.AutoSize = true;
this.lblAddress.Location = new System.Drawing.Point(116, 8);
this.lblAddress.Name = "lblAddress";
this.lblAddress.Size = new System.Drawing.Size(37, 13);
this.lblAddress.TabIndex = 7;
this.lblAddress.Text = "$0000";
//
// chkPauseGameWhileWindowActive
//
this.chkPauseGameWhileWindowActive.Anchor = System.Windows.Forms.AnchorStyles.Left;
this.chkPauseGameWhileWindowActive.AutoSize = true;
this.chkPauseGameWhileWindowActive.Location = new System.Drawing.Point(3, 172);
this.chkPauseGameWhileWindowActive.Name = "chkPauseGameWhileWindowActive";
this.chkPauseGameWhileWindowActive.Size = new System.Drawing.Size(278, 17);
this.chkPauseGameWhileWindowActive.TabIndex = 6;
this.chkPauseGameWhileWindowActive.Text = "Automatically pause game when this window is active";
this.chkPauseGameWhileWindowActive.UseVisualStyleBackColor = true;
this.chkPauseGameWhileWindowActive.CheckedChanged += new System.EventHandler(this.chkPauseGameWhileWindowActive_CheckedChanged);
//
// ctrlCheatFinder
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.Controls.Add(this.tableLayoutPanel1);
this.Name = "ctrlCheatFinder";
this.Size = new System.Drawing.Size(565, 196);
this.grpFilters.ResumeLayout(false);
this.tableLayoutPanel2.ResumeLayout(false);
this.flowLayoutPanel1.ResumeLayout(false);
this.flowLayoutPanel1.PerformLayout();
this.flowLayoutPanel4.ResumeLayout(false);
this.flowLayoutPanel4.PerformLayout();
((System.ComponentModel.ISupportInitialize)(this.nudCurrentFilterValue)).EndInit();
this.tableLayoutPanel1.ResumeLayout(false);
this.tableLayoutPanel1.PerformLayout();
this.contextMenuStrip.ResumeLayout(false);
this.flowLayoutPanel2.ResumeLayout(false);
this.flowLayoutPanel2.PerformLayout();
this.ResumeLayout(false);
}
#endregion
private System.Windows.Forms.Timer tmrRefresh;
private Debugger.Controls.ctrlAddressList lstAddresses;
private System.Windows.Forms.GroupBox grpFilters;
private System.Windows.Forms.Button btnReset;
private System.Windows.Forms.Button btnUndo;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel2;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel1;
private System.Windows.Forms.ComboBox cboPrevFilterType;
private System.Windows.Forms.Button btnAddPrevFilter;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel4;
private System.Windows.Forms.ComboBox cboCurrentFilterType;
private System.Windows.Forms.NumericUpDown nudCurrentFilterValue;
private System.Windows.Forms.Button btnAddCurrentFilter;
private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
private System.Windows.Forms.Button btnCreateCheat;
private System.Windows.Forms.Label lblPreviousValue;
private System.Windows.Forms.Label lblCurrentValue;
private System.Windows.Forms.FlowLayoutPanel flowLayoutPanel2;
private System.Windows.Forms.Label lblAtAddress;
private System.Windows.Forms.Label lblAddress;
private System.Windows.Forms.ContextMenuStrip contextMenuStrip;
private System.Windows.Forms.ToolStripMenuItem mnuCreateCheat;
private System.Windows.Forms.CheckBox chkPauseGameWhileWindowActive;
}
}

View file

@ -0,0 +1,232 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Mesen.GUI.Config;
namespace Mesen.GUI.Forms.Cheats
{
public partial class ctrlCheatFinder : UserControl
{
public event EventHandler OnAddCheat;
public bool TabIsFocused
{
set
{
_tabIsFocused = value;
if(chkPauseGameWhileWindowActive.Checked) {
if(_tabIsFocused) {
InteropEmu.Pause();
} else {
InteropEmu.Resume();
}
}
}
}
private List<byte[]> _memorySnapshots;
private List<FilterInfo> _filters;
private bool _tabIsFocused = true;
private enum CheatPrevFilterType
{
Smaller,
Equal,
NotEqual,
Greater
}
private enum CheatCurrentFilterType
{
Smaller,
Equal,
NotEqual,
Greater
}
private class FilterInfo
{
public CheatCurrentFilterType? CurrentType;
public CheatPrevFilterType? PrevType;
public int Operand;
}
public ctrlCheatFinder()
{
InitializeComponent();
BaseConfigForm.InitializeComboBox(cboPrevFilterType, typeof(CheatPrevFilterType));
BaseConfigForm.InitializeComboBox(cboCurrentFilterType, typeof(CheatCurrentFilterType));
cboPrevFilterType.SelectedIndex = 0;
cboCurrentFilterType.SelectedIndex = 0;
btnUndo.Enabled = false;
if(LicenseManager.UsageMode != LicenseUsageMode.Designtime) {
Reset();
}
}
private void Reset()
{
_filters = new List<FilterInfo>();
_memorySnapshots = new List<byte[]>();
TakeSnapshot();
}
private void TakeSnapshot()
{
if(!InteropEmu.IsRunning()) {
return;
}
byte[] memory = GetSnapshot();
_memorySnapshots.Add(memory);
RefreshAddressList();
UpdateUI();
}
private byte[] GetSnapshot()
{
bool release = !InteropEmu.DebugIsDebuggerRunning();
byte[] memory = InteropEmu.DebugGetInternalRam();
if(release) {
InteropEmu.DebugRelease();
} else {
System.Diagnostics.Debug.Print("test");
}
return memory;
}
private void tmrRefresh_Tick(object sender, EventArgs e)
{
RefreshAddressList();
}
private void RefreshAddressList()
{
UpdateUI();
if(!InteropEmu.IsRunning()) {
return;
}
HashSet<int> matchingAddresses = new HashSet<int>();
for(int i = 0; i < 0x800; i++) {
matchingAddresses.Add(i);
}
if(_memorySnapshots.Count > 1) {
for(int i = 0; i < _memorySnapshots.Count - 1; i++) {
matchingAddresses = new HashSet<int>(matchingAddresses.Where(addr => {
if(_filters[i].PrevType.HasValue) {
switch(_filters[i].PrevType) {
case CheatPrevFilterType.Smaller: return _memorySnapshots[i+1][addr] < _memorySnapshots[i][addr];
case CheatPrevFilterType.Equal: return _memorySnapshots[i+1][addr] == _memorySnapshots[i][addr];
case CheatPrevFilterType.NotEqual: return _memorySnapshots[i+1][addr] != _memorySnapshots[i][addr];
case CheatPrevFilterType.Greater: return _memorySnapshots[i+1][addr] > _memorySnapshots[i][addr];
}
} else {
switch(_filters[i].CurrentType) {
case CheatCurrentFilterType.Smaller: return _memorySnapshots[i+1][addr] < _filters[i].Operand;
case CheatCurrentFilterType.Equal: return _memorySnapshots[i+1][addr] == _filters[i].Operand;
case CheatCurrentFilterType.NotEqual: return _memorySnapshots[i+1][addr] != _filters[i].Operand;
case CheatCurrentFilterType.Greater: return _memorySnapshots[i+1][addr] > _filters[i].Operand;
}
}
return false;
}));
}
}
byte[] memory = GetSnapshot();
List<byte> values = new List<byte>(0x800);
List<int> addresses = new List<int>(0x800);
for(int i = 0; i < 0x800; i++) {
if(matchingAddresses.Contains(i)) {
addresses.Add(i);
values.Add(memory[i]);
}
}
lstAddresses.SetData(values.ToArray(), addresses.ToArray());
}
private void btnReset_Click(object sender, EventArgs e)
{
Reset();
}
private void btnUndo_Click(object sender, EventArgs e)
{
if(_filters.Count > 0) {
_filters.RemoveAt(_filters.Count-1);
_memorySnapshots.RemoveAt(_memorySnapshots.Count-1);
UpdateUI();
}
}
private void UpdateUI()
{
btnUndo.Enabled = _filters.Count > 0;
chkPauseGameWhileWindowActive.Enabled = btnAddCurrentFilter.Enabled = btnAddPrevFilter.Enabled = btnReset.Enabled = cboCurrentFilterType.Enabled = cboPrevFilterType.Enabled = nudCurrentFilterValue.Enabled = InteropEmu.IsRunning();
mnuCreateCheat.Enabled = btnCreateCheat.Enabled = lstAddresses.CurrentAddress.HasValue;
if(lstAddresses.CurrentAddress.HasValue) {
lblAddress.Visible = true;
lblAtAddress.Visible = true;
lblAddress.Text = "$" + lstAddresses.CurrentAddress?.ToString("X4");
} else {
lblAddress.Visible = false;
lblAtAddress.Visible = false;
}
}
private void btnAddPrevFilter_Click(object sender, EventArgs e)
{
_filters.Add(new FilterInfo { PrevType = (CheatPrevFilterType)cboPrevFilterType.SelectedIndex });
TakeSnapshot();
}
private void btnAddCurrentFilter_Click(object sender, EventArgs e)
{
_filters.Add(new FilterInfo { CurrentType = (CheatCurrentFilterType)cboCurrentFilterType.SelectedIndex, Operand = (int)nudCurrentFilterValue.Value });
TakeSnapshot();
}
private void contextMenuStrip_Opening(object sender, CancelEventArgs e)
{
UpdateUI();
}
private void btnCreateCheat_Click(object sender, EventArgs e)
{
RomInfo romInfo = InteropEmu.GetRomInfo();
CheatInfo newCheat = new CheatInfo {
GameCrc = romInfo.GetPrgCrcString(),
GameName = romInfo.GetRomName(),
Address = (uint)lstAddresses.CurrentAddress,
CheatType = CheatType.Custom
};
frmCheat frm = new frmCheat(newCheat);
if(frm.ShowDialog() == DialogResult.OK) {
OnAddCheat?.Invoke(newCheat, new EventArgs());
}
}
private void chkPauseGameWhileWindowActive_CheckedChanged(object sender, EventArgs e)
{
if(chkPauseGameWhileWindowActive.Checked) {
InteropEmu.Pause();
} else {
InteropEmu.Resume();
}
}
}
}

View file

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<metadata name="tmrRefresh.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>17, 17</value>
</metadata>
<metadata name="contextMenuStrip.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>128, 17</value>
</metadata>
</root>

View file

@ -58,8 +58,10 @@ namespace Mesen.GUI.Forms.Cheats
this.btnExportAllCheats = new System.Windows.Forms.ToolStripMenuItem();
this.btnExportGame = new System.Windows.Forms.ToolStripMenuItem();
this.btnExportSelectedCheats = new System.Windows.Forms.ToolStripMenuItem();
this.tpgCheatFinder = new System.Windows.Forms.TabPage();
this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel();
this.chkDisableCheats = new System.Windows.Forms.CheckBox();
this.ctrlCheatFinder = new Mesen.GUI.Forms.Cheats.ctrlCheatFinder();
this.baseConfigPanel.SuspendLayout();
this.tabMain.SuspendLayout();
this.tabCheats.SuspendLayout();
@ -71,6 +73,7 @@ namespace Mesen.GUI.Forms.Cheats
this.contextMenuGames.SuspendLayout();
this.contextMenuCheats.SuspendLayout();
this.tsCheatActions.SuspendLayout();
this.tpgCheatFinder.SuspendLayout();
this.tableLayoutPanel2.SuspendLayout();
this.SuspendLayout();
//
@ -84,6 +87,7 @@ namespace Mesen.GUI.Forms.Cheats
// tabMain
//
this.tabMain.Controls.Add(this.tabCheats);
this.tabMain.Controls.Add(this.tpgCheatFinder);
this.tabMain.Dock = System.Windows.Forms.DockStyle.Fill;
this.tabMain.Location = new System.Drawing.Point(0, 0);
this.tabMain.Margin = new System.Windows.Forms.Padding(0);
@ -370,6 +374,17 @@ namespace Mesen.GUI.Forms.Cheats
this.btnExportSelectedCheats.Text = "Selected Cheats";
this.btnExportSelectedCheats.Click += new System.EventHandler(this.btnExportSelectedCheats_Click);
//
// tpgCheatFinder
//
this.tpgCheatFinder.Controls.Add(this.ctrlCheatFinder);
this.tpgCheatFinder.Location = new System.Drawing.Point(4, 22);
this.tpgCheatFinder.Name = "tpgCheatFinder";
this.tpgCheatFinder.Padding = new System.Windows.Forms.Padding(3);
this.tpgCheatFinder.Size = new System.Drawing.Size(608, 231);
this.tpgCheatFinder.TabIndex = 1;
this.tpgCheatFinder.Text = "Cheat Finder";
this.tpgCheatFinder.UseVisualStyleBackColor = true;
//
// tableLayoutPanel2
//
this.tableLayoutPanel2.ColumnCount = 1;
@ -394,6 +409,14 @@ namespace Mesen.GUI.Forms.Cheats
this.chkDisableCheats.Text = "Disable all cheats";
this.chkDisableCheats.UseVisualStyleBackColor = true;
//
// ctrlCheatFinder
//
this.ctrlCheatFinder.Dock = System.Windows.Forms.DockStyle.Fill;
this.ctrlCheatFinder.Location = new System.Drawing.Point(3, 3);
this.ctrlCheatFinder.Name = "ctrlCheatFinder";
this.ctrlCheatFinder.Size = new System.Drawing.Size(602, 225);
this.ctrlCheatFinder.TabIndex = 0;
//
// frmCheatList
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
@ -404,6 +427,7 @@ namespace Mesen.GUI.Forms.Cheats
this.Name = "frmCheatList";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
this.Text = "Cheats";
this.ShowInTaskbar = true;
this.Controls.SetChildIndex(this.baseConfigPanel, 0);
this.Controls.SetChildIndex(this.tableLayoutPanel2, 0);
this.baseConfigPanel.ResumeLayout(false);
@ -420,6 +444,7 @@ namespace Mesen.GUI.Forms.Cheats
this.contextMenuCheats.ResumeLayout(false);
this.tsCheatActions.ResumeLayout(false);
this.tsCheatActions.PerformLayout();
this.tpgCheatFinder.ResumeLayout(false);
this.tableLayoutPanel2.ResumeLayout(false);
this.ResumeLayout(false);
@ -457,5 +482,7 @@ namespace Mesen.GUI.Forms.Cheats
private System.Windows.Forms.ToolStripSplitButton btnImport;
private System.Windows.Forms.ToolStripMenuItem btnImportCheatDB;
private System.Windows.Forms.ToolStripMenuItem btnImportFromFile;
private System.Windows.Forms.TabPage tpgCheatFinder;
private ctrlCheatFinder ctrlCheatFinder;
}
}

View file

@ -14,7 +14,7 @@ namespace Mesen.GUI.Forms.Cheats
{
public partial class frmCheatList : BaseConfigForm
{
private List<CheatInfo> Cheats { get { return ConfigManager.Config.Cheats; } }
private List<CheatInfo> _cheats;
private GameInfo _selectedItem = null;
public frmCheatList()
@ -25,14 +25,45 @@ namespace Mesen.GUI.Forms.Cheats
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
chkDisableCheats.Checked = ConfigManager.Config.DisableAllCheats;
UpdateGameList();
lstGameList.Select();
if(!DesignMode) {
_cheats = new List<CheatInfo>(ConfigManager.Config.Cheats);
chkDisableCheats.Checked = ConfigManager.Config.DisableAllCheats;
UpdateGameList();
lstGameList.Select();
ctrlCheatFinder.OnAddCheat += CtrlCheatFinder_OnAddCheat;
tabMain.TabIndexChanged += TabMain_TabIndexChanged;
}
}
private void TabMain_TabIndexChanged(object sender, EventArgs e)
{
ctrlCheatFinder.TabIsFocused = (tabMain.SelectedTab == tpgCheatFinder);
}
protected override void OnActivated(EventArgs e)
{
if(tabMain.SelectedTab == tpgCheatFinder) {
ctrlCheatFinder.TabIsFocused = true;
}
base.OnActivated(e);
}
protected override void OnDeactivate(EventArgs e)
{
ctrlCheatFinder.TabIsFocused = false;
base.OnDeactivate(e);
}
private void CtrlCheatFinder_OnAddCheat(object sender, EventArgs e)
{
AddCheats(new List<CheatInfo>() { (CheatInfo)sender });
}
protected override void UpdateConfig()
{
ConfigManager.Config.DisableAllCheats = chkDisableCheats.Checked;
ConfigManager.Config.Cheats = _cheats;
}
private void UpdateGameList(string gameCrc = null)
@ -42,7 +73,7 @@ namespace Mesen.GUI.Forms.Cheats
if(!string.IsNullOrWhiteSpace(romInfo.RomName)) {
nameByCrc[romInfo.GetPrgCrcString()] = romInfo.GetRomName();
}
foreach(CheatInfo cheat in this.Cheats) {
foreach(CheatInfo cheat in _cheats) {
if(!nameByCrc.ContainsKey(cheat.GameCrc)) {
nameByCrc[cheat.GameCrc] = cheat.GameName;
}
@ -99,7 +130,7 @@ namespace Mesen.GUI.Forms.Cheats
lstCheats.Items.Clear();
if(_selectedItem != null) {
string crc32 = _selectedItem.Crc;
foreach(CheatInfo cheat in this.Cheats) {
foreach(CheatInfo cheat in _cheats) {
if(cheat.GameCrc == crc32) {
ListViewItem item = lstCheats.Items.Add(cheat.CheatName);
item.SubItems.Add(cheat.ToString());
@ -163,7 +194,7 @@ namespace Mesen.GUI.Forms.Cheats
{
foreach(ListViewItem item in lstCheats.SelectedItems) {
CheatInfo cheat = item.Tag as CheatInfo;
this.Cheats.Remove(cheat);
_cheats.Remove(cheat);
}
UpdateGameList();
}
@ -177,7 +208,7 @@ namespace Mesen.GUI.Forms.Cheats
{
foreach(var item in lstCheats.Items) {
CheatInfo cheat = ((ListViewItem)item).Tag as CheatInfo;
this.Cheats.Remove(cheat);
_cheats.Remove(cheat);
}
UpdateGameList();
}
@ -209,13 +240,13 @@ namespace Mesen.GUI.Forms.Cheats
{
if(cheats.Count > 0) {
HashSet<string> existingCheats = new HashSet<string>();
foreach(CheatInfo cheat in this.Cheats) {
foreach(CheatInfo cheat in _cheats) {
existingCheats.Add(cheat.GameCrc + cheat.ToString());
}
foreach(CheatInfo cheat in cheats) {
if(!existingCheats.Contains(cheat.GameCrc + cheat.ToString())) {
this.Cheats.Add(cheat);
_cheats.Add(cheat);
}
}
@ -237,12 +268,12 @@ namespace Mesen.GUI.Forms.Cheats
private void btnExportAllCheats_Click(object sender, EventArgs e)
{
ExportCheats(this.Cheats, "MesenCheats.xml");
ExportCheats(_cheats, "MesenCheats.xml");
}
private void btnExportGame_Click(object sender, EventArgs e)
{
ExportCheats(this.Cheats.Where((c) => c.GameCrc == _selectedItem.Crc), _selectedItem.Text + "_Cheats.xml");
ExportCheats(_cheats.Where((c) => c.GameCrc == _selectedItem.Crc), _selectedItem.Text + "_Cheats.xml");
}
private void btnExportSelectedCheats_Click(object sender, EventArgs e)

View file

@ -28,6 +28,7 @@ namespace Mesen.GUI.Forms
{
private static Language _language;
private static XmlDocument _resources = new XmlDocument();
private static XmlDocument _enResources = new XmlDocument();
private static XmlDocument _originalEnglishResources = null;
public static Language GetCurrentLanguage()
@ -54,9 +55,10 @@ namespace Mesen.GUI.Forms
}
string filename;
string enFilename = "resources.en.xml";
switch(language) {
default:
case Language.English: filename = "resources.en.xml"; break;
case Language.English: filename = enFilename; break;
case Language.French: filename = "resources.fr.xml"; break;
case Language.Japanese: filename = "resources.ja.xml"; break;
case Language.Russian: filename = "resources.ru.xml"; break;
@ -68,11 +70,19 @@ namespace Mesen.GUI.Forms
using(Stream stream = ResourceManager.GetZippedResource(filename)) {
_resources.Load(stream);
}
using(Stream stream = ResourceManager.GetZippedResource(enFilename)) {
_enResources.Load(stream);
}
}
public static string GetMessage(string id, params object[] args)
{
var baseNode = _resources.SelectSingleNode("/Resources/Messages/Message[@ID='" + id + "']");
if(baseNode == null) {
baseNode = _enResources.SelectSingleNode("/Resources/Messages/Message[@ID='" + id + "']");
}
if(baseNode != null) {
return string.Format(baseNode.InnerText, args);
} else {
@ -83,6 +93,10 @@ namespace Mesen.GUI.Forms
public static string GetEnumText(Enum e)
{
var baseNode = _resources.SelectSingleNode("/Resources/Enums/Enum[@ID='" + e.GetType().Name + "']/Value[@ID='" + e.ToString() + "']");
if(baseNode == null) {
baseNode = _enResources.SelectSingleNode("/Resources/Enums/Enum[@ID='" + e.GetType().Name + "']/Value[@ID='" + e.ToString() + "']");
}
if(baseNode != null) {
return baseNode.InnerText;
} else {
@ -150,9 +164,6 @@ namespace Mesen.GUI.Forms
ApplyResources(baseNode, ((ContextMenuStrip)ctrl).Items);
} else if(ctrl is ListView) {
ApplyResources(baseNode, ((ListView)ctrl).Columns);
if(((ListView)ctrl).ContextMenuStrip != null) {
ApplyResources(baseNode, ((ListView)ctrl).ContextMenuStrip.Items);
}
} else if(ctrl is ToolStrip) {
ApplyResources(baseNode, ((ToolStrip)ctrl).Items);
} else if(ctrl is ToolStripSplitButton) {
@ -162,6 +173,12 @@ namespace Mesen.GUI.Forms
} else if(ctrl is ToolStripMenuItem) {
ApplyResources(baseNode, ((ToolStripMenuItem)ctrl).DropDownItems);
}
if(ctrl is Control) {
if(((Control)ctrl).ContextMenuStrip != null) {
ApplyResources(baseNode, ((Control)ctrl).ContextMenuStrip.Items);
}
}
}
}

View file

@ -26,6 +26,7 @@ namespace Mesen.GUI.Forms
private Thread _emuThread;
private frmDebugger _debugger;
private frmLogWindow _logWindow;
private frmCheatList _cheatListWindow;
private string _currentRomPath = null;
private int _currentRomArchiveIndex = -1;
private string _currentGame = null;
@ -1028,9 +1029,15 @@ namespace Mesen.GUI.Forms
private void mnuCheats_Click(object sender, EventArgs e)
{
frmCheatList frm = new frmCheatList();
if(frm.ShowDialog(sender, this) == DialogResult.OK) {
CheatInfo.ApplyCheats();
if(_cheatListWindow == null) {
_cheatListWindow = new frmCheatList();
_cheatListWindow.Show(sender, this);
_cheatListWindow.FormClosed += (s, evt) => {
_cheatListWindow = null;
CheatInfo.ApplyCheats();
};
} else {
_cheatListWindow.Focus();
}
}

View file

@ -271,6 +271,12 @@
<Compile Include="Debugger\Controls\ctrlCallstack.Designer.cs">
<DependentUpon>ctrlCallstack.cs</DependentUpon>
</Compile>
<Compile Include="Debugger\Controls\ctrlAddressList.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Debugger\Controls\ctrlAddressList.Designer.cs">
<DependentUpon>ctrlAddressList.cs</DependentUpon>
</Compile>
<Compile Include="Debugger\Controls\ctrlPaletteViewer.cs">
<SubType>UserControl</SubType>
</Compile>
@ -374,6 +380,12 @@
<Compile Include="Forms\BaseConfigForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="Forms\Cheats\ctrlCheatFinder.cs">
<SubType>UserControl</SubType>
</Compile>
<Compile Include="Forms\Cheats\ctrlCheatFinder.Designer.cs">
<DependentUpon>ctrlCheatFinder.cs</DependentUpon>
</Compile>
<Compile Include="Forms\Cheats\FceuxCheatLoader.cs" />
<Compile Include="Forms\Cheats\frmCheat.cs">
<SubType>Form</SubType>
@ -553,6 +565,9 @@
<EmbeddedResource Include="Debugger\Controls\ctrlCallstack.resx">
<DependentUpon>ctrlCallstack.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Debugger\Controls\ctrlAddressList.resx">
<DependentUpon>ctrlAddressList.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Debugger\Controls\ctrlPaletteViewer.resx">
<DependentUpon>ctrlPaletteViewer.cs</DependentUpon>
</EmbeddedResource>
@ -604,6 +619,9 @@
<EmbeddedResource Include="Forms\BaseForm.resx">
<DependentUpon>BaseForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Cheats\ctrlCheatFinder.resx">
<DependentUpon>ctrlCheatFinder.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Forms\Cheats\frmCheat.resx">
<DependentUpon>frmCheat.cs</DependentUpon>
</EmbeddedResource>

View file

@ -157,6 +157,7 @@ namespace Mesen.GUI
[DllImport(DLLPath)] public static extern void SetAudioDevice(string audioDevice);
[DllImport(DLLPath)] public static extern void DebugInitialize();
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool DebugIsDebuggerRunning();
[DllImport(DLLPath)] public static extern void DebugRelease();
[DllImport(DLLPath)] public static extern void DebugSetFlags(DebuggerFlags flags);
[DllImport(DLLPath)] public static extern void DebugGetState(ref DebugState state);
@ -196,6 +197,19 @@ namespace Mesen.GUI
return buffer;
}
public static byte[] DebugGetInternalRam()
{
byte[] buffer = new byte[0x800];
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try {
UInt32 memorySize = InteropEmu.DebugGetMemoryStateWrapper(DebugMemoryType.InternalRam, handle.AddrOfPinnedObject());
Array.Resize(ref buffer, (int)memorySize);
} finally {
handle.Free();
}
return buffer;
}
[DllImport(DLLPath, EntryPoint="DebugGetNametable")] private static extern void DebugGetNametableWrapper(UInt32 nametableIndex, IntPtr frameBuffer, IntPtr tileData, IntPtr attributeData);
public static void DebugGetNametable(int nametableIndex, out byte[] frameData, out byte[] tileData, out byte[] attributeData)
{
@ -888,6 +902,7 @@ namespace Mesen.GUI
PrgRom = 5,
ChrRom = 6,
ChrRam = 7,
InternalRam = 8
}
public class MD5Helper

View file

@ -21,6 +21,11 @@ extern "C"
Console::GetInstance()->StopDebugger();
}
DllExport bool __stdcall DebugIsDebuggerRunning()
{
return Console::GetInstance()->GetDebugger(false).get() != nullptr;
}
DllExport void __stdcall DebugSetFlags(uint32_t flags) { GetDebugger()->SetFlags(flags); }
DllExport void __stdcall DebugGetState(DebugState *state) { GetDebugger()->GetState(state); }