1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Drawing; 5 using System.Data; 6 using System.Linq; 7 using System.Text; 8 using System.Threading.Tasks; 9 using System.Windows.Forms; 10 using Mesen.GUI.Config; 11 using Mesen.GUI.Controls; 12 13 namespace Mesen.GUI.Forms.Cheats 14 { 15 public partial class ctrlCheatFinder : BaseControl 16 { 17 public event EventHandler OnAddCheat; 18 public bool TabIsFocused 19 { 20 set 21 { 22 _tabIsFocused = value; 23 if(chkPauseGameWhileWindowActive.Checked) { 24 if(_tabIsFocused) { 25 InteropEmu.Pause(); 26 } else { 27 InteropEmu.Resume(); 28 } 29 } 30 } 31 } 32 33 private List<byte[]> _memorySnapshots; 34 private List<FilterInfo> _filters; 35 private bool _tabIsFocused = false; 36 37 private enum CheatPrevFilterType 38 { 39 Smaller, 40 Equal, 41 NotEqual, 42 Greater 43 } 44 45 private enum CheatCurrentFilterType 46 { 47 Smaller, 48 Equal, 49 NotEqual, 50 Greater 51 } 52 53 private class FilterInfo 54 { 55 public CheatCurrentFilterType? CurrentType; 56 public CheatPrevFilterType? PrevType; 57 public int Operand; 58 } 59 ctrlCheatFinder()60 public ctrlCheatFinder() 61 { 62 InitializeComponent(); 63 64 BaseConfigForm.InitializeComboBox(cboPrevFilterType, typeof(CheatPrevFilterType)); 65 BaseConfigForm.InitializeComboBox(cboCurrentFilterType, typeof(CheatCurrentFilterType)); 66 cboPrevFilterType.SelectedIndex = 0; 67 cboCurrentFilterType.SelectedIndex = 0; 68 69 btnUndo.Enabled = false; 70 71 if(LicenseManager.UsageMode != LicenseUsageMode.Designtime) { 72 Reset(); 73 tmrRefresh.Start(); 74 } 75 } 76 Reset()77 private void Reset() 78 { 79 _filters = new List<FilterInfo>(); 80 _memorySnapshots = new List<byte[]>(); 81 TakeSnapshot(); 82 } 83 TakeSnapshot()84 private void TakeSnapshot() 85 { 86 if(!InteropEmu.IsRunning()) { 87 return; 88 } 89 90 byte[] memory = GetSnapshot(); 91 _memorySnapshots.Add(memory); 92 RefreshAddressList(); 93 94 UpdateUI(); 95 } 96 GetSnapshot()97 private byte[] GetSnapshot() 98 { 99 bool release = !InteropEmu.DebugIsDebuggerRunning(); 100 byte[] memory = InteropEmu.DebugGetInternalRam(); 101 if(release) { 102 InteropEmu.DebugRelease(); 103 } 104 105 return memory; 106 } 107 tmrRefresh_Tick(object sender, EventArgs e)108 private void tmrRefresh_Tick(object sender, EventArgs e) 109 { 110 if(_tabIsFocused) { 111 RefreshAddressList(); 112 } 113 } 114 RefreshAddressList()115 private void RefreshAddressList() 116 { 117 UpdateUI(); 118 if(!InteropEmu.IsRunning()) { 119 return; 120 } 121 122 HashSet<int> matchingAddresses = new HashSet<int>(); 123 for(int i = 0; i < 0x800; i++) { 124 matchingAddresses.Add(i); 125 } 126 127 if(_memorySnapshots.Count > 1) { 128 for(int i = 0; i < _memorySnapshots.Count - 1; i++) { 129 matchingAddresses = new HashSet<int>(matchingAddresses.Where(addr => { 130 if(_filters[i].PrevType.HasValue) { 131 switch(_filters[i].PrevType) { 132 case CheatPrevFilterType.Smaller: return _memorySnapshots[i+1][addr] > _memorySnapshots[i][addr]; 133 case CheatPrevFilterType.Equal: return _memorySnapshots[i+1][addr] == _memorySnapshots[i][addr]; 134 case CheatPrevFilterType.NotEqual: return _memorySnapshots[i+1][addr] != _memorySnapshots[i][addr]; 135 case CheatPrevFilterType.Greater: return _memorySnapshots[i+1][addr] < _memorySnapshots[i][addr]; 136 } 137 } else { 138 switch(_filters[i].CurrentType) { 139 case CheatCurrentFilterType.Smaller: return _memorySnapshots[i+1][addr] < _filters[i].Operand; 140 case CheatCurrentFilterType.Equal: return _memorySnapshots[i+1][addr] == _filters[i].Operand; 141 case CheatCurrentFilterType.NotEqual: return _memorySnapshots[i+1][addr] != _filters[i].Operand; 142 case CheatCurrentFilterType.Greater: return _memorySnapshots[i+1][addr] > _filters[i].Operand; 143 } 144 } 145 return false; 146 })); 147 } 148 } 149 150 byte[] memory = GetSnapshot(); 151 List<byte> values = new List<byte>(0x800); 152 List<int> addresses = new List<int>(0x800); 153 for(int i = 0; i < 0x800; i++) { 154 if(matchingAddresses.Contains(i)) { 155 addresses.Add(i); 156 values.Add(memory[i]); 157 } 158 } 159 lstAddresses.SetData(values.ToArray(), addresses.ToArray()); 160 } 161 btnReset_Click(object sender, EventArgs e)162 private void btnReset_Click(object sender, EventArgs e) 163 { 164 Reset(); 165 } 166 btnUndo_Click(object sender, EventArgs e)167 private void btnUndo_Click(object sender, EventArgs e) 168 { 169 if(_filters.Count > 0) { 170 _filters.RemoveAt(_filters.Count-1); 171 _memorySnapshots.RemoveAt(_memorySnapshots.Count-1); 172 UpdateUI(); 173 } 174 } 175 UpdateUI()176 private void UpdateUI() 177 { 178 btnUndo.Enabled = _filters.Count > 0; 179 chkPauseGameWhileWindowActive.Enabled = btnAddCurrentFilter.Enabled = btnAddPrevFilter.Enabled = btnReset.Enabled = cboCurrentFilterType.Enabled = cboPrevFilterType.Enabled = nudCurrentFilterValue.Enabled = InteropEmu.IsRunning(); 180 mnuCreateCheat.Enabled = btnCreateCheat.Enabled = lstAddresses.CurrentAddress.HasValue; 181 182 if(lstAddresses.CurrentAddress.HasValue) { 183 lblAddress.Visible = true; 184 lblAtAddress.Visible = true; 185 lblAddress.Text = "$" + lstAddresses.CurrentAddress?.ToString("X4"); 186 } else { 187 lblAddress.Visible = false; 188 lblAtAddress.Visible = false; 189 } 190 } 191 btnAddPrevFilter_Click(object sender, EventArgs e)192 private void btnAddPrevFilter_Click(object sender, EventArgs e) 193 { 194 _filters.Add(new FilterInfo { PrevType = (CheatPrevFilterType)cboPrevFilterType.SelectedIndex }); 195 TakeSnapshot(); 196 } 197 btnAddCurrentFilter_Click(object sender, EventArgs e)198 private void btnAddCurrentFilter_Click(object sender, EventArgs e) 199 { 200 _filters.Add(new FilterInfo { CurrentType = (CheatCurrentFilterType)cboCurrentFilterType.SelectedIndex, Operand = (int)nudCurrentFilterValue.Value }); 201 TakeSnapshot(); 202 } 203 contextMenuStrip_Opening(object sender, CancelEventArgs e)204 private void contextMenuStrip_Opening(object sender, CancelEventArgs e) 205 { 206 UpdateUI(); 207 } 208 btnCreateCheat_Click(object sender, EventArgs e)209 private void btnCreateCheat_Click(object sender, EventArgs e) 210 { 211 RomInfo romInfo = InteropEmu.GetRomInfo(); 212 CheatInfo newCheat = new CheatInfo { 213 GameCrc = romInfo.GetPrgCrcString(), 214 GameName = romInfo.GetRomName(), 215 Address = (uint)lstAddresses.CurrentAddress, 216 CheatType = CheatType.Custom 217 }; 218 219 using(frmCheat frm = new frmCheat(newCheat)) { 220 if(frm.ShowDialog() == DialogResult.OK) { 221 OnAddCheat?.Invoke(newCheat, new EventArgs()); 222 } 223 } 224 } 225 chkPauseGameWhileWindowActive_CheckedChanged(object sender, EventArgs e)226 private void chkPauseGameWhileWindowActive_CheckedChanged(object sender, EventArgs e) 227 { 228 if(chkPauseGameWhileWindowActive.Checked) { 229 InteropEmu.Pause(); 230 } else { 231 InteropEmu.Resume(); 232 } 233 } 234 } 235 } 236