diff --git a/Core/Console.cpp b/Core/Console.cpp index 4ef40726..a6d682a6 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -448,10 +448,10 @@ void Console::LoadState(uint8_t *buffer, uint32_t bufferSize) LoadState(stream); } -std::shared_ptr Console::GetDebugger() +std::shared_ptr 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; diff --git a/Core/Console.h b/Core/Console.h index c8a4d87e..4fc08136 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -59,7 +59,7 @@ class Console //Used to resume the emu loop after calling Pause() static void Resume(); - std::shared_ptr GetDebugger(); + std::shared_ptr GetDebugger(bool autoStart = true); void StopDebugger(); static NesModel GetNesModel(); diff --git a/Core/Debugger.cpp b/Core/Debugger.cpp index 0d89a444..e79d4f4a 100644 --- a/Core/Debugger.cpp +++ b/Core/Debugger.cpp @@ -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; } diff --git a/Core/Debugger.h b/Core/Debugger.h index 768d8181..b60a8ed9 100644 --- a/Core/Debugger.h +++ b/Core/Debugger.h @@ -28,6 +28,7 @@ enum class DebugMemoryType PrgRom = 5, ChrRom = 6, ChrRam = 7, + InternalRam = 8, }; enum class DebuggerFlags diff --git a/GUI.NET/Debugger/Controls/ctrlAddressList.Designer.cs b/GUI.NET/Debugger/Controls/ctrlAddressList.Designer.cs new file mode 100644 index 00000000..e82309e4 --- /dev/null +++ b/GUI.NET/Debugger/Controls/ctrlAddressList.Designer.cs @@ -0,0 +1,81 @@ +namespace Mesen.GUI.Debugger.Controls +{ + partial class ctrlAddressList + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + 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; + } +} diff --git a/GUI.NET/Debugger/Controls/ctrlAddressList.cs b/GUI.NET/Debugger/Controls/ctrlAddressList.cs new file mode 100644 index 00000000..db20deea --- /dev/null +++ b/GUI.NET/Debugger/Controls/ctrlAddressList.cs @@ -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; + } + } + } + } +} diff --git a/GUI.NET/Debugger/Controls/ctrlAddressList.resx b/GUI.NET/Debugger/Controls/ctrlAddressList.resx new file mode 100644 index 00000000..8766f298 --- /dev/null +++ b/GUI.NET/Debugger/Controls/ctrlAddressList.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + \ No newline at end of file diff --git a/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs b/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs index a6bea179..8c898f73 100644 --- a/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs +++ b/GUI.NET/Debugger/Controls/ctrlScrollableTextbox.cs @@ -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; diff --git a/GUI.NET/Debugger/Controls/ctrlTextbox.cs b/GUI.NET/Debugger/Controls/ctrlTextbox.cs index cf79f7cc..2e5673d4 100644 --- a/GUI.NET/Debugger/Controls/ctrlTextbox.cs +++ b/GUI.NET/Debugger/Controls/ctrlTextbox.cs @@ -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()) { diff --git a/GUI.NET/Dependencies/resources.en.xml b/GUI.NET/Dependencies/resources.en.xml index cd71f374..e87b546e 100644 --- a/GUI.NET/Dependencies/resources.en.xml +++ b/GUI.NET/Dependencies/resources.en.xml @@ -130,5 +130,17 @@ All 1s Random Values + + Smaller than + Equal to + Not equal to + Greater than + + + Smaller + Equal + Not equal + Greater + \ No newline at end of file diff --git a/GUI.NET/Dependencies/resources.fr.xml b/GUI.NET/Dependencies/resources.fr.xml index 4bd486ae..19fd0863 100644 --- a/GUI.NET/Dependencies/resources.fr.xml +++ b/GUI.NET/Dependencies/resources.fr.xml @@ -364,6 +364,19 @@ Exporter les codes sélectionnés Exporter Désactiver tous les codes + + Recherche de codes + Réinitialiser + Annuler + La valeur courante est + La valeur précédente était + Ajouter le filtre + Ajouter le filtre + Créer un code + Créer un code + à + Mettre le jeu à pause automatiquement lorsque cette fenêtre est active + OK Annuler @@ -540,5 +553,17 @@ Tous les bits à 1 Valeurs aléatoires + + Plus petite que + Égale à + Pas égale à + Plus grand que + + + Plus petite + Égale + Pas égale + Plus grande + \ No newline at end of file diff --git a/GUI.NET/Dependencies/resources.ja.xml b/GUI.NET/Dependencies/resources.ja.xml index 0a41a0e1..3f2cf297 100644 --- a/GUI.NET/Dependencies/resources.ja.xml +++ b/GUI.NET/Dependencies/resources.ja.xml @@ -352,6 +352,19 @@ 選択中のコードをエクスポートする エクスポート チートコード機能を無効にする + + コードファインダー + リセット + 元に戻す + 現在の数値は + 前回の数値は現在の数値 + フィルター追加 + フィルター追加 + コード作成 + コード作成 + + このウィンドウがアクティブの時、自動的にゲームをポーズする + OK キャンセル @@ -523,5 +536,17 @@ ビット全てを1にする 乱数 + + 次の数値より小さい + 次の数値と同じ + 次の数値とは違う + 次の数値より大きい + + + より小さい + と同じ + とは違う + より大きい + \ No newline at end of file diff --git a/GUI.NET/Forms/BaseConfigForm.cs b/GUI.NET/Forms/BaseConfigForm.cs index 995d3419..0cb5656e 100644 --- a/GUI.NET/Forms/BaseConfigForm.cs +++ b/GUI.NET/Forms/BaseConfigForm.cs @@ -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 { diff --git a/GUI.NET/Forms/BaseForm.cs b/GUI.NET/Forms/BaseForm.cs index 48e8c465..ad75ec32 100644 --- a/GUI.NET/Forms/BaseForm.cs +++ b/GUI.NET/Forms/BaseForm.cs @@ -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) { diff --git a/GUI.NET/Forms/Cheats/ctrlCheatFinder.Designer.cs b/GUI.NET/Forms/Cheats/ctrlCheatFinder.Designer.cs new file mode 100644 index 00000000..34117683 --- /dev/null +++ b/GUI.NET/Forms/Cheats/ctrlCheatFinder.Designer.cs @@ -0,0 +1,368 @@ +namespace Mesen.GUI.Forms.Cheats +{ + partial class ctrlCheatFinder + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if(disposing && (components != null)) { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + 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; + } +} diff --git a/GUI.NET/Forms/Cheats/ctrlCheatFinder.cs b/GUI.NET/Forms/Cheats/ctrlCheatFinder.cs new file mode 100644 index 00000000..228ded04 --- /dev/null +++ b/GUI.NET/Forms/Cheats/ctrlCheatFinder.cs @@ -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 _memorySnapshots; + private List _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(); + _memorySnapshots = new List(); + 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 matchingAddresses = new HashSet(); + 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(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 values = new List(0x800); + List addresses = new List(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(); + } + } + } +} diff --git a/GUI.NET/Forms/Cheats/ctrlCheatFinder.resx b/GUI.NET/Forms/Cheats/ctrlCheatFinder.resx new file mode 100644 index 00000000..4c13e842 --- /dev/null +++ b/GUI.NET/Forms/Cheats/ctrlCheatFinder.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 17, 17 + + + 128, 17 + + \ No newline at end of file diff --git a/GUI.NET/Forms/Cheats/frmCheatList.Designer.cs b/GUI.NET/Forms/Cheats/frmCheatList.Designer.cs index f15b4495..2caa8fb0 100644 --- a/GUI.NET/Forms/Cheats/frmCheatList.Designer.cs +++ b/GUI.NET/Forms/Cheats/frmCheatList.Designer.cs @@ -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; } } \ No newline at end of file diff --git a/GUI.NET/Forms/Cheats/frmCheatList.cs b/GUI.NET/Forms/Cheats/frmCheatList.cs index d8695c8e..c2f521fb 100644 --- a/GUI.NET/Forms/Cheats/frmCheatList.cs +++ b/GUI.NET/Forms/Cheats/frmCheatList.cs @@ -14,7 +14,7 @@ namespace Mesen.GUI.Forms.Cheats { public partial class frmCheatList : BaseConfigForm { - private List Cheats { get { return ConfigManager.Config.Cheats; } } + private List _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(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)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 existingCheats = new HashSet(); - 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) diff --git a/GUI.NET/Forms/ResourceHelper.cs b/GUI.NET/Forms/ResourceHelper.cs index 94c19cd2..4361e65e 100644 --- a/GUI.NET/Forms/ResourceHelper.cs +++ b/GUI.NET/Forms/ResourceHelper.cs @@ -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); + } + } } } diff --git a/GUI.NET/Forms/frmMain.cs b/GUI.NET/Forms/frmMain.cs index c9f42558..c0e12fc4 100644 --- a/GUI.NET/Forms/frmMain.cs +++ b/GUI.NET/Forms/frmMain.cs @@ -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(); } } diff --git a/GUI.NET/GUI.NET.csproj b/GUI.NET/GUI.NET.csproj index 25e39677..876d50c8 100644 --- a/GUI.NET/GUI.NET.csproj +++ b/GUI.NET/GUI.NET.csproj @@ -271,6 +271,12 @@ ctrlCallstack.cs + + UserControl + + + ctrlAddressList.cs + UserControl @@ -374,6 +380,12 @@ Form + + UserControl + + + ctrlCheatFinder.cs + Form @@ -553,6 +565,9 @@ ctrlCallstack.cs + + ctrlAddressList.cs + ctrlPaletteViewer.cs @@ -604,6 +619,9 @@ BaseForm.cs + + ctrlCheatFinder.cs + frmCheat.cs diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index 6c0b0502..a407e8fd 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -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 diff --git a/InteropDLL/DebugWrapper.cpp b/InteropDLL/DebugWrapper.cpp index f9a15e9d..e945bdc2 100644 --- a/InteropDLL/DebugWrapper.cpp +++ b/InteropDLL/DebugWrapper.cpp @@ -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); }